diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c
index 3c4ba66f5f4a546866d99772bf0874962a98d3b4..ddf925cc47b44e17ea34f99f94cbe796097bc4a2 100644
--- a/src/core/statistics/census_tracing.c
+++ b/src/core/statistics/census_tracing.c
@@ -32,35 +32,19 @@
  */
 
 #include "src/core/statistics/census_interface.h"
+#include "src/core/statistics/census_tracing.h"
 
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/statistics/census_rpc_stats.h"
 #include "src/core/statistics/hash_table.h"
 #include "src/core/support/string.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-
-/* Struct for a trace annotation. */
-typedef struct annotation {
-  gpr_timespec ts;                            /* timestamp of the annotation */
-  char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */
-  struct annotation* next;
-} annotation;
-
-typedef struct trace_obj {
-  census_op_id id;
-  gpr_timespec ts;
-  census_rpc_stats rpc_stats;
-  char* method;
-  annotation* annotations;
-} trace_obj;
-
-static void trace_obj_destroy(trace_obj* obj) {
+
+void trace_obj_destroy(trace_obj* obj) {
   annotation* p = obj->annotations;
   while (p != NULL) {
     annotation* next = p->next;
@@ -207,3 +191,45 @@ trace_obj* census_get_trace_obj_locked(census_op_id op_id) {
 const char* census_get_trace_method_name(const trace_obj* trace) {
   return (const char*)trace->method;
 }
+
+static annotation* dup_annotation_chain(annotation* from) {
+  annotation* to = NULL;
+  if (from != NULL) {
+    to = gpr_malloc(sizeof(annotation));
+    memcpy(to, from, sizeof(annotation));
+    to->next = dup_annotation_chain(from->next);
+  }
+  return to;
+}
+
+static trace_obj* trace_obj_dup(trace_obj* from) {
+  trace_obj* to = NULL;
+  GPR_ASSERT(from != NULL);
+  to = gpr_malloc(sizeof(trace_obj));
+  to->id = from->id;
+  to->ts = from->ts;
+  to->rpc_stats = from->rpc_stats;
+  to->method = gpr_strdup(from->method);
+  to->annotations = dup_annotation_chain(from->annotations);
+  return to;
+}
+
+trace_obj** census_get_active_ops(int* num_active_ops) {
+  trace_obj** ret = NULL;
+  gpr_mu_lock(&g_mu);
+  if (g_trace_store != NULL) {
+    size_t n = 0;
+    census_ht_kv* all_kvs = census_ht_get_all_elements(g_trace_store, &n);
+    *num_active_ops = n;
+    if (n != 0 ) {
+      size_t i = 0;
+      ret = gpr_malloc(sizeof(trace_obj *) * n);
+      for (i = 0; i < n; i++) {
+        ret[i] = trace_obj_dup((trace_obj*)all_kvs[i].v);
+      }
+    }
+    gpr_free(all_kvs);
+  }
+  gpr_mu_unlock(&g_mu);
+  return ret;
+}
diff --git a/src/core/statistics/census_tracing.h b/src/core/statistics/census_tracing.h
index f356c9424d51d31cc27465da6d10f7ae81043f19..58333f7f6b8cc24785397561013885ef9eb0b03b 100644
--- a/src/core/statistics/census_tracing.h
+++ b/src/core/statistics/census_tracing.h
@@ -34,12 +34,35 @@
 #ifndef __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_
 #define __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_
 
+#include <grpc/support/time.h>
+#include "src/core/statistics/census_rpc_stats.h"
+
+/* WARNING: The data structures and APIs provided by this file are for GRPC
+   library's internal use ONLY. They might be changed in backward-incompatible
+   ways and are not subject to any deprecation policy.
+   They are not recommended for external use.
+ */
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* Opaque structure for trace object */
-typedef struct trace_obj trace_obj;
+/* Struct for a trace annotation. */
+typedef struct annotation {
+  gpr_timespec ts;                            /* timestamp of the annotation */
+  char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */
+  struct annotation* next;
+} annotation;
+
+typedef struct trace_obj {
+  census_op_id id;
+  gpr_timespec ts;
+  census_rpc_stats rpc_stats;
+  char* method;
+  annotation* annotations;
+} trace_obj;
+
+/* Deletes trace object. */
+void trace_obj_destroy(trace_obj* obj);
 
 /* Initializes trace store. This function is thread safe. */
 void census_tracing_init(void);
@@ -60,6 +83,12 @@ void census_internal_unlock_trace_store(void);
 /* Gets method tag name associated with the input trace object. */
 const char* census_get_trace_method_name(const trace_obj* trace);
 
+/* Returns an array of pointers to trace objects of currently active operations
+   and fills in number of active operations. Returns NULL if there's no active
+   operations.
+   Caller owns the returned objects. */
+trace_obj** census_get_active_ops(int* num_active_ops);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/test/core/statistics/trace_test.c b/test/core/statistics/trace_test.c
index 6eafcf145686a9bd1936d55db4338054f4c808d1..18edfb433aabff2d842ffcc59e824c240a69a17d 100644
--- a/test/core/statistics/trace_test.c
+++ b/test/core/statistics/trace_test.c
@@ -32,10 +32,12 @@
  */
 
 #include <string.h>
+#include <stdio.h>
 
 #include "src/core/statistics/census_interface.h"
 #include "src/core/statistics/census_tracing.h"
 #include "src/core/statistics/census_tracing.h"
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/sync.h>
@@ -172,6 +174,74 @@ static void test_trace_print(void) {
   census_tracing_shutdown();
 }
 
+/* Returns 1 if two ids are equal, otherwise returns 0. */
+static int ids_equal(census_op_id id1, census_op_id id2) {
+  return (id1.upper == id2.upper) && (id1.lower == id2.lower);
+}
+
+static void test_get_active_ops(void) {
+  census_op_id id_1, id_2, id_3;
+  trace_obj** active_ops;
+  const char* annotation_txt[] = {"annotation 1", "a2"};
+  int i = 0;
+  int n = 0;
+
+  gpr_log(GPR_INFO, "test_get_active_ops");
+  census_tracing_init();
+  /* No active ops before calling start_op(). */
+  active_ops = census_get_active_ops(&n);
+  GPR_ASSERT(active_ops == NULL);
+  GPR_ASSERT(n == 0);
+
+  /* Starts one op */
+  id_1 = census_tracing_start_op();
+  census_add_method_tag(id_1, "foo_1");
+  active_ops = census_get_active_ops(&n);
+  GPR_ASSERT(active_ops != NULL);
+  GPR_ASSERT(n == 1);
+  GPR_ASSERT(ids_equal(active_ops[0]->id, id_1));
+  trace_obj_destroy(active_ops[0]);
+  gpr_free(active_ops);
+  active_ops = NULL;
+
+  /* Start the second and the third ops */
+  id_2 = census_tracing_start_op();
+  census_add_method_tag(id_2, "foo_2");
+  id_3 = census_tracing_start_op();
+  census_add_method_tag(id_3, "foo_3");
+
+  active_ops = census_get_active_ops(&n);
+  GPR_ASSERT(n == 3);
+  for (i = 0; i < 3; i++) {
+    trace_obj_destroy(active_ops[i]);
+  }
+  gpr_free(active_ops);
+  active_ops = NULL;
+
+  /* End the second op  and add annotations to the third ops*/
+  census_tracing_end_op(id_2);
+  census_tracing_print(id_3, annotation_txt[0]);
+  census_tracing_print(id_3, annotation_txt[1]);
+
+  active_ops = census_get_active_ops(&n);
+  GPR_ASSERT(active_ops != NULL);
+  GPR_ASSERT(n == 2);
+  for (i = 0; i < 2; i++) {
+    trace_obj_destroy(active_ops[i]);
+  }
+  gpr_free(active_ops);
+  active_ops = NULL;
+
+  /* End all ops. */
+  census_tracing_end_op(id_1);
+  census_tracing_end_op(id_3);
+  active_ops = census_get_active_ops(&n);
+  GPR_ASSERT(active_ops == NULL);
+  GPR_ASSERT(n == 0);
+
+  census_tracing_shutdown();
+}
+
 int main(int argc, char** argv) {
   grpc_test_init(argc, argv);
   test_init_shutdown();
@@ -180,5 +250,6 @@ int main(int argc, char** argv) {
   test_concurrency();
   test_add_method_tag_to_unknown_op_id();
   test_trace_print();
+  test_get_active_ops();
   return 0;
 }