From a193adb70919f2ffb8e61edfb4d899b78ad5efeb Mon Sep 17 00:00:00 2001
From: Xiao Yu <fishx@google.com>
Date: Thu, 18 Apr 2019 14:25:12 -0700
Subject: [PATCH] Refactor monitoring gauge and sampler API to an object-based
 API.

PiperOrigin-RevId: 244258066
---
 tensorflow/c/eager/c_api_experimental.cc      | 406 +++++++++++++++---
 tensorflow/c/eager/c_api_experimental.h       | 187 +++++++-
 tensorflow/c/eager/c_api_experimental_test.cc | 111 ++++-
 tensorflow/c/eager/c_api_internal.h           |  94 ++++
 tensorflow/python/eager/BUILD                 |   4 +-
 tensorflow/python/eager/monitoring.py         | 339 +++++++++++++--
 tensorflow/python/eager/monitoring_test.py    |  58 ++-
 tensorflow/python/pywrap_tfe.i                |  48 ++-
 8 files changed, 1124 insertions(+), 123 deletions(-)

diff --git a/tensorflow/c/eager/c_api_experimental.cc b/tensorflow/c/eager/c_api_experimental.cc
index 6cbd73fac0e..acf7e9c92d0 100644
--- a/tensorflow/c/eager/c_api_experimental.cc
+++ b/tensorflow/c/eager/c_api_experimental.cc
@@ -99,59 +99,6 @@ bool TFE_ProfilerClientStartTracing(const char* service_addr,
   return s.ok();
 }
 
-static tensorflow::mutex gauges_map_lock(tensorflow::LINKER_INITIALIZED);
-
-static std::unordered_map<string,
-                          tensorflow::monitoring::Gauge<tensorflow::int64, 1>*>*
-get_gauges_map() EXCLUSIVE_LOCKS_REQUIRED(gauges_map_lock) {
-  static std::unordered_map<
-      string, tensorflow::monitoring::Gauge<tensorflow::int64, 1>*>*
-      gauges_map = new std::unordered_map<
-          string, tensorflow::monitoring::Gauge<tensorflow::int64, 1>*>;
-  return gauges_map;
-}
-
-static tensorflow::mutex samplers_map_lock(tensorflow::LINKER_INITIALIZED);
-
-static std::unordered_map<string, tensorflow::monitoring::Sampler<1>*>*
-get_samplers_map() EXCLUSIVE_LOCKS_REQUIRED(samplers_map_lock) {
-  static std::unordered_map<string, tensorflow::monitoring::Sampler<1>*>*
-      samplers_map =
-          new std::unordered_map<string, tensorflow::monitoring::Sampler<1>*>;
-  return samplers_map;
-}
-
-void TFE_MonitoringSetGauge(const char* name, const char* label,
-                            int64_t value) {
-  tensorflow::mutex_lock l(gauges_map_lock);
-  auto gauges_map = get_gauges_map();
-  if (gauges_map->find(name) == gauges_map->end()) {
-    gauges_map->emplace(
-        name, tensorflow::monitoring::Gauge<tensorflow::int64, 1>::New(
-                  name,
-                  tensorflow::strings::StrCat(
-                      name, " :Gauge metric collected from Python API."),
-                  "metric_descriptor"));
-  }
-  gauges_map->at(name)->GetCell(label)->Set(value);
-}
-
-void TFE_MonitoringAddSampler(const char* name, const char* label,
-                              double value) {
-  tensorflow::mutex_lock l(samplers_map_lock);
-  auto samplers_map = get_samplers_map();
-  if (samplers_map->find(name) == samplers_map->end()) {
-    samplers_map->emplace(
-        name, tensorflow::monitoring::Sampler<1>::New(
-                  {name,
-                   tensorflow::strings::StrCat(
-                       name, " :Counter metric collected from Python API."),
-                   "metric_descriptor"},
-                  {tensorflow::monitoring::Buckets::Exponential(1, 2, 30)}));
-  }
-  samplers_map->at(name)->GetCell(label)->Add(value);
-}
-
 void TFE_MonitoringCounterCellIncrementBy(TFE_MonitoringCounterCell* cell,
                                           int64_t value) {
   cell->cell.IncrementBy(value);
@@ -166,6 +113,10 @@ TFE_MonitoringCounter0* TFE_MonitoringNewCounter0(const char* name,
                                                   const char* description) {
   auto* result = new TFE_MonitoringCounter0({name, description});
   Set_TF_Status_from_Status(status, result->counter->GetStatus());
+  if (!result->counter->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
   return result;
 }
 
@@ -185,6 +136,10 @@ TFE_MonitoringCounter1* TFE_MonitoringNewCounter1(const char* name,
                                                   const char* label1) {
   auto* result = new TFE_MonitoringCounter1({name, description, label1});
   Set_TF_Status_from_Status(status, result->counter->GetStatus());
+  if (!result->counter->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
   return result;
 }
 
@@ -206,6 +161,10 @@ TFE_MonitoringCounter2* TFE_MonitoringNewCounter2(const char* name,
   auto* result =
       new TFE_MonitoringCounter2({name, description, label1, label2});
   Set_TF_Status_from_Status(status, result->counter->GetStatus());
+  if (!result->counter->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
   return result;
 }
 
@@ -218,3 +177,344 @@ TFE_MonitoringCounterCell* TFE_MonitoringGetCellCounter2(
   return static_cast<TFE_MonitoringCounterCell*>(
       static_cast<void*>(counter->counter->GetCell(label1, label2)));
 }
+
+void TFE_MonitoringIntGaugeCellSet(TFE_MonitoringIntGaugeCell* cell,
+                                   int64_t value) {
+  cell->cell.Set(value);
+}
+
+int64_t TFE_MonitoringIntGaugeCellValue(TFE_MonitoringIntGaugeCell* cell) {
+  return cell->cell.value();
+}
+
+TFE_MonitoringIntGauge0* TFE_MonitoringNewIntGauge0(const char* name,
+                                                    TF_Status* status,
+                                                    const char* description) {
+  auto* result = new TFE_MonitoringIntGauge0({name, description});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteIntGauge0(TFE_MonitoringIntGauge0* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringIntGaugeCell* TFE_MonitoringGetCellIntGauge0(
+    TFE_MonitoringIntGauge0* gauge) {
+  return static_cast<TFE_MonitoringIntGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell()));
+}
+
+TFE_MonitoringIntGauge1* TFE_MonitoringNewIntGauge1(const char* name,
+                                                    TF_Status* status,
+                                                    const char* description,
+                                                    const char* label1) {
+  auto* result = new TFE_MonitoringIntGauge1({name, description, label1});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteIntGauge1(TFE_MonitoringIntGauge1* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringIntGaugeCell* TFE_MonitoringGetCellIntGauge1(
+    TFE_MonitoringIntGauge1* gauge, const char* label1) {
+  return static_cast<TFE_MonitoringIntGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell(label1)));
+}
+
+TFE_MonitoringIntGauge2* TFE_MonitoringNewIntGauge2(const char* name,
+                                                    TF_Status* status,
+                                                    const char* description,
+                                                    const char* label1,
+                                                    const char* label2) {
+  auto* result =
+      new TFE_MonitoringIntGauge2({name, description, label1, label2});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteIntGauge2(TFE_MonitoringIntGauge2* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringIntGaugeCell* TFE_MonitoringGetCellIntGauge2(
+    TFE_MonitoringIntGauge2* gauge, const char* label1, const char* label2) {
+  return static_cast<TFE_MonitoringIntGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell(label1, label2)));
+}
+
+void TFE_MonitoringStringGaugeCellSet(TFE_MonitoringStringGaugeCell* cell,
+                                      const char* value) {
+  cell->cell.Set({value});
+}
+
+const void TFE_MonitoringStringGaugeCellValue(
+    TFE_MonitoringStringGaugeCell* cell, TF_Buffer* buf) {
+  tensorflow::string value = cell->cell.value();
+  void* data = tensorflow::port::Malloc(value.length());
+  value.copy(static_cast<char*>(data), value.length(), 0);
+  buf->data = data;
+  buf->length = value.length();
+  buf->data_deallocator = [](void* data, size_t length) {
+    tensorflow::port::Free(data);
+  };
+}
+
+TFE_MonitoringStringGauge0* TFE_MonitoringNewStringGauge0(
+    const char* name, TF_Status* status, const char* description) {
+  auto* result = new TFE_MonitoringStringGauge0({name, description});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteStringGauge0(TFE_MonitoringStringGauge0* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringStringGaugeCell* TFE_MonitoringGetCellStringGauge0(
+    TFE_MonitoringStringGauge0* gauge) {
+  return static_cast<TFE_MonitoringStringGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell()));
+}
+
+TFE_MonitoringStringGauge1* TFE_MonitoringNewStringGauge1(
+    const char* name, TF_Status* status, const char* description,
+    const char* label1) {
+  auto* result = new TFE_MonitoringStringGauge1({name, description, label1});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteStringGauge1(TFE_MonitoringStringGauge1* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringStringGaugeCell* TFE_MonitoringGetCellStringGauge1(
+    TFE_MonitoringStringGauge1* gauge, const char* label1) {
+  return static_cast<TFE_MonitoringStringGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell(label1)));
+}
+
+TFE_MonitoringStringGauge2* TFE_MonitoringNewStringGauge2(
+    const char* name, TF_Status* status, const char* description,
+    const char* label1, const char* label2) {
+  auto* result =
+      new TFE_MonitoringStringGauge2({name, description, label1, label2});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteStringGauge2(TFE_MonitoringStringGauge2* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringStringGaugeCell* TFE_MonitoringGetCellStringGauge2(
+    TFE_MonitoringStringGauge2* gauge, const char* label1, const char* label2) {
+  return static_cast<TFE_MonitoringStringGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell(label1, label2)));
+}
+
+void TFE_MonitoringBoolGaugeCellSet(TFE_MonitoringBoolGaugeCell* cell,
+                                    bool value) {
+  cell->cell.Set(value);
+}
+
+bool TFE_MonitoringBoolGaugeCellValue(TFE_MonitoringBoolGaugeCell* cell) {
+  return cell->cell.value();
+}
+
+TFE_MonitoringBoolGauge0* TFE_MonitoringNewBoolGauge0(const char* name,
+                                                      TF_Status* status,
+                                                      const char* description) {
+  auto* result = new TFE_MonitoringBoolGauge0({name, description});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteBoolGauge0(TFE_MonitoringBoolGauge0* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringBoolGaugeCell* TFE_MonitoringGetCellBoolGauge0(
+    TFE_MonitoringBoolGauge0* gauge) {
+  return static_cast<TFE_MonitoringBoolGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell()));
+}
+
+TFE_MonitoringBoolGauge1* TFE_MonitoringNewBoolGauge1(const char* name,
+                                                      TF_Status* status,
+                                                      const char* description,
+                                                      const char* label1) {
+  auto* result = new TFE_MonitoringBoolGauge1({name, description, label1});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteBoolGauge1(TFE_MonitoringBoolGauge1* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringBoolGaugeCell* TFE_MonitoringGetCellBoolGauge1(
+    TFE_MonitoringBoolGauge1* gauge, const char* label1) {
+  return static_cast<TFE_MonitoringBoolGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell(label1)));
+}
+
+TFE_MonitoringBoolGauge2* TFE_MonitoringNewBoolGauge2(const char* name,
+                                                      TF_Status* status,
+                                                      const char* description,
+                                                      const char* label1,
+                                                      const char* label2) {
+  auto* result =
+      new TFE_MonitoringBoolGauge2({name, description, label1, label2});
+  Set_TF_Status_from_Status(status, result->gauge->GetStatus());
+  if (!result->gauge->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteBoolGauge2(TFE_MonitoringBoolGauge2* gauge) {
+  delete gauge;
+}
+
+TFE_MonitoringBoolGaugeCell* TFE_MonitoringGetCellBoolGauge2(
+    TFE_MonitoringBoolGauge2* gauge, const char* label1, const char* label2) {
+  return static_cast<TFE_MonitoringBoolGaugeCell*>(
+      static_cast<void*>(gauge->gauge->GetCell(label1, label2)));
+}
+
+void TFE_MonitoringSamplerCellAdd(TFE_MonitoringSamplerCell* cell,
+                                  double value) {
+  cell->cell.Add(value);
+}
+
+void TFE_MonitoringSamplerCellValue(TFE_MonitoringSamplerCell* cell,
+                                    TF_Buffer* buf) {
+  string content;
+  cell->cell.value().SerializeToString(&content);
+  void* data = tensorflow::port::Malloc(content.length());
+  content.copy(static_cast<char*>(data), content.length(), 0);
+  buf->data = data;
+  buf->length = content.length();
+  buf->data_deallocator = [](void* data, size_t length) {
+    tensorflow::port::Free(data);
+  };
+}
+
+TFE_MonitoringBuckets* TFE_MonitoringNewExponentialBuckets(double scale,
+                                                           double growth_factor,
+                                                           int bucket_count) {
+  return new TFE_MonitoringBuckets([scale, growth_factor, bucket_count]() {
+    return tensorflow::monitoring::Buckets::Exponential(scale, growth_factor,
+                                                        bucket_count);
+  });
+}
+
+void TFE_MonitoringDeleteBuckets(TFE_MonitoringBuckets* buckets) {
+  delete buckets;
+}
+
+TFE_MonitoringSampler0* TFE_MonitoringNewSampler0(
+    const char* name, TFE_MonitoringBuckets* buckets, TF_Status* status,
+    const char* description) {
+  auto* result = new TFE_MonitoringSampler0(
+      {name, buckets->create_buckets(), description});
+  Set_TF_Status_from_Status(status, result->sampler->GetStatus());
+  if (!result->sampler->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteSampler0(TFE_MonitoringSampler0* sampler) {
+  delete sampler;
+}
+
+TFE_MonitoringSamplerCell* TFE_MonitoringGetCellSampler0(
+    TFE_MonitoringSampler0* sampler) {
+  return static_cast<TFE_MonitoringSamplerCell*>(
+      static_cast<void*>(sampler->sampler->GetCell()));
+}
+
+TFE_MonitoringSampler1* TFE_MonitoringNewSampler1(
+    const char* name, TFE_MonitoringBuckets* buckets, TF_Status* status,
+    const char* description, const char* label1) {
+  auto* result = new TFE_MonitoringSampler1(
+      {name, buckets->create_buckets(), description, label1});
+  Set_TF_Status_from_Status(status, result->sampler->GetStatus());
+  if (!result->sampler->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteSampler1(TFE_MonitoringSampler1* sampler) {
+  delete sampler;
+}
+
+TFE_MonitoringSamplerCell* TFE_MonitoringGetCellSampler1(
+    TFE_MonitoringSampler1* sampler, const char* label1) {
+  return static_cast<TFE_MonitoringSamplerCell*>(
+      static_cast<void*>(sampler->sampler->GetCell(label1)));
+}
+
+TFE_MonitoringSampler2* TFE_MonitoringNewSampler2(
+    const char* name, TFE_MonitoringBuckets* buckets, TF_Status* status,
+    const char* description, const char* label1, const char* label2) {
+  auto* result = new TFE_MonitoringSampler2(
+      {name, buckets->create_buckets(), description, label1, label2});
+  Set_TF_Status_from_Status(status, result->sampler->GetStatus());
+  if (!result->sampler->GetStatus().ok()) {
+    delete result;
+    return nullptr;
+  }
+  return result;
+}
+
+void TFE_MonitoringDeleteSampler2(TFE_MonitoringSampler2* sampler) {
+  delete sampler;
+}
+
+TFE_MonitoringSamplerCell* TFE_MonitoringGetCellSampler2(
+    TFE_MonitoringSampler2* sampler, const char* label1, const char* label2) {
+  return static_cast<TFE_MonitoringSamplerCell*>(
+      static_cast<void*>(sampler->sampler->GetCell(label1, label2)));
+}
diff --git a/tensorflow/c/eager/c_api_experimental.h b/tensorflow/c/eager/c_api_experimental.h
index 11fed825d15..4dc57e1eec5 100644
--- a/tensorflow/c/eager/c_api_experimental.h
+++ b/tensorflow/c/eager/c_api_experimental.h
@@ -87,19 +87,7 @@ TF_CAPI_EXPORT extern bool TFE_ProfilerClientStartTracing(
     const char* service_addr, const char* logdir, const char* worker_list,
     bool include_dataset_ops, int duration_ms, int num_tracing_attempts);
 
-// Set the value of a Gauge metric. If the metric with given name does not
-// exist, it will create a new Gauge metric. Right now it only supports type
-// int64, consider to add more type supports if needed.
-TF_CAPI_EXPORT extern void TFE_MonitoringSetGauge(const char* name,
-                                                  const char* label,
-                                                  int64_t value);
-
-// Add the given value to a Sampler metric. If the metric with given name
-// does not exist, it will create a new Sampler metric.
-TF_CAPI_EXPORT extern void TFE_MonitoringAddSampler(const char* name,
-                                                    const char* label,
-                                                    double value);
-
+// TODO(fishx): Move these monitoring APIs into a separate file.
 // -----------------------------------------------------------------------------
 // Monitoring Counter APIs.
 // These APIs de-templated monitoring Counter for swig.
@@ -149,6 +137,179 @@ TF_CAPI_EXPORT extern void TFE_MonitoringDeleteCounter2(
 TF_CAPI_EXPORT extern TFE_MonitoringCounterCell* TFE_MonitoringGetCellCounter2(
     TFE_MonitoringCounter2* counter, const char* label1, const char* label2);
 
+// -----------------------------------------------------------------------------
+// Monitoring Gauge APIs.
+// These APIs de-templated monitoring Gauge for swig.
+
+typedef struct TFE_MonitoringIntGaugeCell TFE_MonitoringIntGaugeCell;
+
+// Atomically set the value of the cell.
+TF_CAPI_EXPORT extern void TFE_MonitoringIntGaugeCellSet(
+    TFE_MonitoringIntGaugeCell* cell, int64_t value);
+
+// Retrieves the current value of the cell.
+TF_CAPI_EXPORT extern int64_t TFE_MonitoringIntGaugeCellValue(
+    TFE_MonitoringIntGaugeCell* cell);
+
+// APIs for Int Gauge without label.
+typedef struct TFE_MonitoringIntGauge0 TFE_MonitoringIntGauge0;
+TF_CAPI_EXPORT extern TFE_MonitoringIntGauge0* TFE_MonitoringNewIntGauge0(
+    const char* name, TF_Status* out_status, const char* description);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteIntGauge0(
+    TFE_MonitoringIntGauge0* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringIntGaugeCell*
+TFE_MonitoringGetCellIntGauge0(TFE_MonitoringIntGauge0* gauge);
+
+// APIs for Int Gauge with 1 label.
+typedef struct TFE_MonitoringIntGauge1 TFE_MonitoringIntGauge1;
+TF_CAPI_EXPORT extern TFE_MonitoringIntGauge1* TFE_MonitoringNewIntGauge1(
+    const char* name, TF_Status* out_status, const char* description,
+    const char* label1);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteIntGauge1(
+    TFE_MonitoringIntGauge1* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringIntGaugeCell*
+TFE_MonitoringGetCellIntGauge1(TFE_MonitoringIntGauge1* gauge,
+                               const char* label1);
+
+// APIs for Int Gauge with 2 label.
+typedef struct TFE_MonitoringIntGauge2 TFE_MonitoringIntGauge2;
+TF_CAPI_EXPORT extern TFE_MonitoringIntGauge2* TFE_MonitoringNewIntGauge2(
+    const char* name, TF_Status* out_status, const char* description,
+    const char* label1, const char* label2);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteIntGauge2(
+    TFE_MonitoringIntGauge2* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringIntGaugeCell*
+TFE_MonitoringGetCellIntGauge2(TFE_MonitoringIntGauge2* gauge,
+                               const char* label1, const char* label2);
+
+typedef struct TFE_MonitoringStringGaugeCell TFE_MonitoringStringGaugeCell;
+TF_CAPI_EXPORT extern void TFE_MonitoringStringGaugeCellSet(
+    TFE_MonitoringStringGaugeCell* cell, const char* value);
+// Retrieves the string value and saves it in buffer.
+TF_CAPI_EXPORT extern const void TFE_MonitoringStringGaugeCellValue(
+    TFE_MonitoringStringGaugeCell* cell, TF_Buffer* buf);
+
+// APIs for String Gauge without label.
+typedef struct TFE_MonitoringStringGauge0 TFE_MonitoringStringGauge0;
+TF_CAPI_EXPORT extern TFE_MonitoringStringGauge0* TFE_MonitoringNewStringGauge0(
+    const char* name, TF_Status* out_status, const char* description);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteStringGauge0(
+    TFE_MonitoringStringGauge0* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringStringGaugeCell*
+TFE_MonitoringGetCellStringGauge0(TFE_MonitoringStringGauge0* gauge);
+
+// APIs for String Gauge with 1 label.
+typedef struct TFE_MonitoringStringGauge1 TFE_MonitoringStringGauge1;
+TF_CAPI_EXPORT extern TFE_MonitoringStringGauge1* TFE_MonitoringNewStringGauge1(
+    const char* name, TF_Status* out_status, const char* description,
+    const char* label1);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteStringGauge1(
+    TFE_MonitoringStringGauge1* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringStringGaugeCell*
+TFE_MonitoringGetCellStringGauge1(TFE_MonitoringStringGauge1* gauge,
+                                  const char* label1);
+
+// APIs for String Gauge with 2 label.
+typedef struct TFE_MonitoringStringGauge2 TFE_MonitoringStringGauge2;
+TF_CAPI_EXPORT extern TFE_MonitoringStringGauge2* TFE_MonitoringNewStringGauge2(
+    const char* name, TF_Status* out_status, const char* description,
+    const char* label1, const char* label2);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteStringGauge2(
+    TFE_MonitoringStringGauge2* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringStringGaugeCell*
+TFE_MonitoringGetCellStringGauge2(TFE_MonitoringStringGauge2* gauge,
+                                  const char* label1, const char* label2);
+
+typedef struct TFE_MonitoringBoolGaugeCell TFE_MonitoringBoolGaugeCell;
+TF_CAPI_EXPORT extern void TFE_MonitoringBoolGaugeCellSet(
+    TFE_MonitoringBoolGaugeCell* cell, bool value);
+TF_CAPI_EXPORT extern bool TFE_MonitoringBoolGaugeCellValue(
+    TFE_MonitoringBoolGaugeCell* cell);
+
+// APIs for Bool Gauge without label.
+typedef struct TFE_MonitoringBoolGauge0 TFE_MonitoringBoolGauge0;
+TF_CAPI_EXPORT extern TFE_MonitoringBoolGauge0* TFE_MonitoringNewBoolGauge0(
+    const char* name, TF_Status* out_status, const char* description);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteBoolGauge0(
+    TFE_MonitoringBoolGauge0* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringBoolGaugeCell*
+TFE_MonitoringGetCellBoolGauge0(TFE_MonitoringBoolGauge0* gauge);
+
+// APIs for Bool Gauge with 1 label.
+typedef struct TFE_MonitoringBoolGauge1 TFE_MonitoringBoolGauge1;
+TF_CAPI_EXPORT extern TFE_MonitoringBoolGauge1* TFE_MonitoringNewBoolGauge1(
+    const char* name, TF_Status* out_status, const char* description,
+    const char* label1);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteBoolGauge1(
+    TFE_MonitoringBoolGauge1* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringBoolGaugeCell*
+TFE_MonitoringGetCellBoolGauge1(TFE_MonitoringBoolGauge1* gauge,
+                                const char* label1);
+
+// APIs for Bool Gauge with 2 label.
+typedef struct TFE_MonitoringBoolGauge2 TFE_MonitoringBoolGauge2;
+TF_CAPI_EXPORT extern TFE_MonitoringBoolGauge2* TFE_MonitoringNewBoolGauge2(
+    const char* name, TF_Status* out_status, const char* description,
+    const char* label1, const char* label2);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteBoolGauge2(
+    TFE_MonitoringBoolGauge2* gauge);
+TF_CAPI_EXPORT extern TFE_MonitoringBoolGaugeCell*
+TFE_MonitoringGetCellBoolGauge2(TFE_MonitoringBoolGauge2* gauge,
+                                const char* label1, const char* label2);
+
+// -----------------------------------------------------------------------------
+// Monitoring Sampler APIs.
+// These APIs de-templated monitoring Sampler for swig.
+
+typedef struct TFE_MonitoringSamplerCell TFE_MonitoringSamplerCell;
+
+// Atomically add the value of the cell.
+TF_CAPI_EXPORT extern void TFE_MonitoringSamplerCellAdd(
+    TFE_MonitoringSamplerCell* cell, double value);
+
+// Retrieves the current value of the cell. The return value is a HistogramProto
+// saved in buffer.
+TF_CAPI_EXPORT extern void TFE_MonitoringSamplerCellValue(
+    TFE_MonitoringSamplerCell* cell, TF_Buffer* buf);
+
+// APIs for sampler buckets
+typedef struct TFE_MonitoringBuckets TFE_MonitoringBuckets;
+TF_CAPI_EXPORT extern TFE_MonitoringBuckets*
+TFE_MonitoringNewExponentialBuckets(double scale, double growth_factor,
+                                    int bucket_count);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteBuckets(
+    TFE_MonitoringBuckets* buckets);
+
+// APIs for Sampler without label.
+typedef struct TFE_MonitoringSampler0 TFE_MonitoringSampler0;
+TF_CAPI_EXPORT extern TFE_MonitoringSampler0* TFE_MonitoringNewSampler0(
+    const char* name, TFE_MonitoringBuckets* buckets, TF_Status* out_status,
+    const char* description);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteSampler0(
+    TFE_MonitoringSampler0* sampler);
+TF_CAPI_EXPORT extern TFE_MonitoringSamplerCell* TFE_MonitoringGetCellSampler0(
+    TFE_MonitoringSampler0* sampler);
+
+// APIs for Sampler with 1 label.
+typedef struct TFE_MonitoringSampler1 TFE_MonitoringSampler1;
+TF_CAPI_EXPORT extern TFE_MonitoringSampler1* TFE_MonitoringNewSampler1(
+    const char* name, TFE_MonitoringBuckets* buckets, TF_Status* out_status,
+    const char* description, const char* label1);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteSampler1(
+    TFE_MonitoringSampler1* sampler);
+TF_CAPI_EXPORT extern TFE_MonitoringSamplerCell* TFE_MonitoringGetCellSampler1(
+    TFE_MonitoringSampler1* sampler, const char* label1);
+
+// APIs for Sampler with 2 label.
+typedef struct TFE_MonitoringSampler2 TFE_MonitoringSampler2;
+TF_CAPI_EXPORT extern TFE_MonitoringSampler2* TFE_MonitoringNewSampler2(
+    const char* name, TFE_MonitoringBuckets* buckets, TF_Status* out_status,
+    const char* description, const char* label1, const char* label2);
+TF_CAPI_EXPORT extern void TFE_MonitoringDeleteSampler2(
+    TFE_MonitoringSampler2* sampler);
+TF_CAPI_EXPORT extern TFE_MonitoringSamplerCell* TFE_MonitoringGetCellSampler2(
+    TFE_MonitoringSampler2* sampler, const char* label1, const char* label2);
+
 #ifdef __cplusplus
 } /* end extern "C" */
 #endif
diff --git a/tensorflow/c/eager/c_api_experimental_test.cc b/tensorflow/c/eager/c_api_experimental_test.cc
index 3f45dd7679e..4e48a7591a9 100644
--- a/tensorflow/c/eager/c_api_experimental_test.cc
+++ b/tensorflow/c/eager/c_api_experimental_test.cc
@@ -131,23 +131,6 @@ TEST(CAPI, MultipleProfilerSession) {
   TFE_DeleteProfilerContext(profiler_context);
 }
 
-TEST(CAPI, MonitoringSetGauge) {
-  TFE_MonitoringSetGauge("test/gauge", "label", 1);
-  auto* collection_registry = monitoring::CollectionRegistry::Default();
-  monitoring::CollectionRegistry::CollectMetricsOptions options;
-  std::unique_ptr<monitoring::CollectedMetrics> metrics =
-      collection_registry->CollectMetrics(options);
-
-  EXPECT_EQ("test/gauge", metrics->point_set_map.at("test/gauge")->metric_name);
-  EXPECT_EQ(1,
-            metrics->point_set_map.at("test/gauge")->points.at(0)->int64_value);
-
-  TFE_MonitoringSetGauge("test/gauge", "label", 5);
-  metrics = collection_registry->CollectMetrics(options);
-  EXPECT_EQ(5,
-            metrics->point_set_map.at("test/gauge")->points.at(0)->int64_value);
-}
-
 TEST(CAPI, MonitoringCounter0) {
   TF_Status* status = TF_NewStatus();
   auto* counter =
@@ -200,8 +183,59 @@ TEST(CAPI, MonitoringCounterMultiple) {
   TFE_MonitoringDeleteCounter2(counter2);
 }
 
-TEST(CAPI, MonitoringAddSampler) {
-  TFE_MonitoringAddSampler("test/sampler", "label", 1.0);
+TEST(CAPI, MonitoringGauge0) {
+  TF_Status* status = TF_NewStatus();
+  auto* gauge = TFE_MonitoringNewIntGauge0("test/gauge", status, "test");
+  CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+  auto* cell = TFE_MonitoringGetCellIntGauge0(gauge);
+  TFE_MonitoringIntGaugeCellSet(cell, 1);
+  EXPECT_EQ(TFE_MonitoringIntGaugeCellValue(cell), 1);
+  auto* collection_registry = monitoring::CollectionRegistry::Default();
+  monitoring::CollectionRegistry::CollectMetricsOptions options;
+  std::unique_ptr<monitoring::CollectedMetrics> metrics =
+      collection_registry->CollectMetrics(options);
+
+  EXPECT_EQ("test/gauge", metrics->point_set_map.at("test/gauge")->metric_name);
+  EXPECT_EQ(1,
+            metrics->point_set_map.at("test/gauge")->points.at(0)->int64_value);
+
+  TFE_MonitoringIntGaugeCellSet(cell, 5);
+  metrics = collection_registry->CollectMetrics(options);
+  EXPECT_EQ(5,
+            metrics->point_set_map.at("test/gauge")->points.at(0)->int64_value);
+  TF_DeleteStatus(status);
+}
+
+TEST(CAPI, MonitoringMultipleGauge) {
+  TF_Status* status = TF_NewStatus();
+  auto* gauge1 =
+      TFE_MonitoringNewBoolGauge1("test/gauge1", status, "test", "label1");
+  CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+  auto* cell1 = TFE_MonitoringGetCellBoolGauge1(gauge1, "foo");
+  TFE_MonitoringBoolGaugeCellSet(cell1, true);
+  EXPECT_TRUE(TFE_MonitoringBoolGaugeCellValue(cell1));
+
+  auto* gauge2 = TFE_MonitoringNewStringGauge2("test/gauge2", status, "test",
+                                               "label1", "label2");
+  CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+  auto* cell2 = TFE_MonitoringGetCellStringGauge2(gauge2, "foo", "bar");
+  TFE_MonitoringStringGaugeCellSet(cell2, "str");
+  auto* buf = new TF_Buffer;
+  TFE_MonitoringStringGaugeCellValue(cell2, buf);
+  string data(static_cast<const char*>(buf->data), buf->length);
+  delete buf;
+  EXPECT_EQ(data, "str");
+  TF_DeleteStatus(status);
+}
+
+TEST(CAPI, MonitoringSampler0) {
+  TF_Status* status = TF_NewStatus();
+  auto* buckets = TFE_MonitoringNewExponentialBuckets(1.0, 2.0, 2);
+  auto* sampler =
+      TFE_MonitoringNewSampler0("test/sampler", buckets, status, "test");
+  CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+  auto* cell = TFE_MonitoringGetCellSampler0(sampler);
+  TFE_MonitoringSamplerCellAdd(cell, 1.0);
   auto* collection_registry = monitoring::CollectionRegistry::Default();
   monitoring::CollectionRegistry::CollectMetricsOptions options;
   std::unique_ptr<monitoring::CollectedMetrics> metrics =
@@ -213,11 +247,48 @@ TEST(CAPI, MonitoringAddSampler) {
                      ->points.at(0)
                      ->histogram_value.sum());
 
-  TFE_MonitoringAddSampler("test/sampler", "label", 5.0);
+  TFE_MonitoringSamplerCellAdd(cell, 5.0);
   metrics = collection_registry->CollectMetrics(options);
   EXPECT_EQ(6.0, metrics->point_set_map.at("test/sampler")
                      ->points.at(0)
                      ->histogram_value.sum());
+  TFE_MonitoringDeleteBuckets(buckets);
+  TF_DeleteStatus(status);
+}
+
+TEST(CAPI, MonitoringMultipleSampler) {
+  TF_Status* status = TF_NewStatus();
+  auto* buckets = TFE_MonitoringNewExponentialBuckets(1.0, 2.0, 2);
+  auto* sampler1 = TFE_MonitoringNewSampler1("test/sampler1", buckets, status,
+                                             "test", "label1");
+  CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+  auto* cell1 = TFE_MonitoringGetCellSampler1(sampler1, "foo");
+  TFE_MonitoringSamplerCellAdd(cell1, 1.0);
+  TFE_MonitoringSamplerCellAdd(cell1, 2.0);
+  TF_Buffer* result1 = TF_NewBuffer();
+  TFE_MonitoringSamplerCellValue(cell1, result1);
+  tensorflow::HistogramProto hitogram1;
+  EXPECT_TRUE(hitogram1.ParseFromString(
+      {reinterpret_cast<const char*>(result1->data), result1->length}));
+  EXPECT_EQ(hitogram1.sum(), 3.0);
+  delete result1;
+
+  auto* sampler2 = TFE_MonitoringNewSampler2("test/sampler2", buckets, status,
+                                             "test", "label1", "label2");
+  CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+  auto* cell2 = TFE_MonitoringGetCellSampler2(sampler2, "foo", "bar");
+  TFE_MonitoringSamplerCellAdd(cell2, 2.0);
+  TFE_MonitoringSamplerCellAdd(cell2, 3.0);
+  TF_Buffer* result2 = TF_NewBuffer();
+  TFE_MonitoringSamplerCellValue(cell2, result2);
+  tensorflow::HistogramProto hitogram2;
+  EXPECT_TRUE(hitogram2.ParseFromString(
+      {reinterpret_cast<const char*>(result2->data), result2->length}));
+  EXPECT_EQ(hitogram2.sum(), 5.0);
+  delete result2;
+
+  TFE_MonitoringDeleteBuckets(buckets);
+  TF_DeleteStatus(status);
 }
 
 }  // namespace
diff --git a/tensorflow/c/eager/c_api_internal.h b/tensorflow/c/eager/c_api_internal.h
index 30711086168..f8ba50fda2e 100644
--- a/tensorflow/c/eager/c_api_internal.h
+++ b/tensorflow/c/eager/c_api_internal.h
@@ -50,6 +50,8 @@ limitations under the License.
 #include "tensorflow/core/lib/gtl/map_util.h"
 #include "tensorflow/core/lib/gtl/stl_util.h"
 #include "tensorflow/core/lib/monitoring/counter.h"
+#include "tensorflow/core/lib/monitoring/gauge.h"
+#include "tensorflow/core/lib/monitoring/sampler.h"
 #include "tensorflow/core/platform/mutex.h"
 #include "tensorflow/core/platform/thread_annotations.h"
 #include "tensorflow/core/profiler/lib/profiler_session.h"
@@ -159,6 +161,98 @@ struct TFE_MonitoringCounter2 : TFE_MonitoringCounter<2> {
   using TFE_MonitoringCounter::TFE_MonitoringCounter;
 };
 
+struct TFE_MonitoringIntGaugeCell {
+  tensorflow::monitoring::GaugeCell<tensorflow::int64> cell;
+};
+struct TFE_MonitoringStringGaugeCell {
+  tensorflow::monitoring::GaugeCell<tensorflow::string> cell;
+};
+struct TFE_MonitoringBoolGaugeCell {
+  tensorflow::monitoring::GaugeCell<bool> cell;
+};
+
+template <typename ValueType, int NumLabels>
+struct TFE_MonitoringGauge {
+  template <typename... LabelDesc>
+  TFE_MonitoringGauge(const char* name, const char* description,
+                      LabelDesc&&... label) {
+    gauge = absl::WrapUnique(
+        tensorflow::monitoring::Gauge<ValueType, NumLabels>::New(
+            name, description, label...));
+  }
+
+  std::unique_ptr<tensorflow::monitoring::Gauge<ValueType, NumLabels>> gauge;
+};
+
+struct TFE_MonitoringIntGauge0 : TFE_MonitoringGauge<tensorflow::int64, 0> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+struct TFE_MonitoringIntGauge1 : TFE_MonitoringGauge<tensorflow::int64, 1> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+struct TFE_MonitoringIntGauge2 : TFE_MonitoringGauge<tensorflow::int64, 2> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+
+struct TFE_MonitoringStringGauge0 : TFE_MonitoringGauge<tensorflow::string, 0> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+struct TFE_MonitoringStringGauge1 : TFE_MonitoringGauge<tensorflow::string, 1> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+struct TFE_MonitoringStringGauge2 : TFE_MonitoringGauge<tensorflow::string, 2> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+
+struct TFE_MonitoringBoolGauge0 : TFE_MonitoringGauge<bool, 0> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+struct TFE_MonitoringBoolGauge1 : TFE_MonitoringGauge<bool, 1> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+struct TFE_MonitoringBoolGauge2 : TFE_MonitoringGauge<bool, 2> {
+  using TFE_MonitoringGauge::TFE_MonitoringGauge;
+};
+
+struct TFE_MonitoringBuckets {
+  TFE_MonitoringBuckets(
+      std::function<std::unique_ptr<tensorflow::monitoring::Buckets>(void)>
+          fn) {
+    create_buckets = fn;
+  }
+
+  std::function<std::unique_ptr<tensorflow::monitoring::Buckets>(void)>
+      create_buckets;
+};
+
+struct TFE_MonitoringSamplerCell {
+  tensorflow::monitoring::SamplerCell cell;
+};
+
+template <int NumLabels>
+struct TFE_MonitoringSampler {
+  template <typename... LabelDesc>
+  TFE_MonitoringSampler(
+      const char* name,
+      std::unique_ptr<tensorflow::monitoring::Buckets> buckets,
+      const char* description, LabelDesc&&... label) {
+    sampler = absl::WrapUnique(tensorflow::monitoring::Sampler<NumLabels>::New(
+        {name, description, label...}, std::move(buckets)));
+  }
+
+  std::unique_ptr<tensorflow::monitoring::Sampler<NumLabels>> sampler;
+};
+
+struct TFE_MonitoringSampler0 : TFE_MonitoringSampler<0> {
+  using TFE_MonitoringSampler::TFE_MonitoringSampler;
+};
+struct TFE_MonitoringSampler1 : TFE_MonitoringSampler<1> {
+  using TFE_MonitoringSampler::TFE_MonitoringSampler;
+};
+struct TFE_MonitoringSampler2 : TFE_MonitoringSampler<2> {
+  using TFE_MonitoringSampler::TFE_MonitoringSampler;
+};
+
 namespace tensorflow {
 // Set an AttrValue on the op. Doesn't handle the list types.
 void SetOpAttrValueScalar(TFE_Context* ctx, TFE_Op* op,
diff --git a/tensorflow/python/eager/BUILD b/tensorflow/python/eager/BUILD
index 17d038348e8..458ac15df22 100644
--- a/tensorflow/python/eager/BUILD
+++ b/tensorflow/python/eager/BUILD
@@ -1,6 +1,6 @@
 licenses(["notice"])  # Apache 2.0
 
-load("//tensorflow:tensorflow.bzl", "tf_py_test", "tf_cc_binary")
+load("//tensorflow:tensorflow.bzl", "tf_py_test")
 load("//tensorflow:tensorflow.bzl", "cuda_py_test")
 load(
     "//tensorflow/tools/test:performance.bzl",
@@ -102,7 +102,9 @@ py_library(
     srcs_version = "PY2AND3",
     visibility = ["//tensorflow:internal"],
     deps = [
+        "//tensorflow/python:c_api_util",
         "//tensorflow/python:pywrap_tensorflow",
+        "//tensorflow/python:util",
     ],
 )
 
diff --git a/tensorflow/python/eager/monitoring.py b/tensorflow/python/eager/monitoring.py
index 335c2fdea57..fd4717f7905 100644
--- a/tensorflow/python/eager/monitoring.py
+++ b/tensorflow/python/eager/monitoring.py
@@ -20,7 +20,10 @@ from __future__ import print_function
 
 import collections
 
+from tensorflow.core.framework import summary_pb2
 from tensorflow.python import pywrap_tensorflow
+from tensorflow.python.framework import c_api_util
+from tensorflow.python.util import compat
 
 _MetricMethod = collections.namedtuple('MetricMethod', 'create delete get_cell')
 _counter_methods = [
@@ -37,32 +40,62 @@ _counter_methods = [
         delete=pywrap_tensorflow.TFE_MonitoringDeleteCounter2,
         get_cell=pywrap_tensorflow.TFE_MonitoringGetCellCounter2),
 ]
-
-
-def gauge(name, label, value):
-  """Set the value of a Gauge metric.
-
-  If the metric with this name does not exist, it will create a new metric.
-
-  Args:
-    name: metric name
-    label: long label
-    value: a int64 value
-  """
-  pywrap_tensorflow.TFE_MonitoringSetGauge(name, label, value)
-
-
-def sampler(name, label, value):
-  """Add the value of a Sampler metric.
-
-  If the metric with this name does not exist, it will create a new metric.
-
-  Args:
-    name: metric name
-    label: metric label
-    value: a double value
-  """
-  pywrap_tensorflow.TFE_MonitoringAddSampler(name, label, value)
+_int_gauge_methods = [
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewIntGauge0,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteIntGauge0,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellIntGauge0),
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewIntGauge1,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteIntGauge1,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellIntGauge1),
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewIntGauge2,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteIntGauge2,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellIntGauge2),
+]
+_string_gauge_methods = [
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewStringGauge0,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteStringGauge0,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellStringGauge0),
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewStringGauge1,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteStringGauge1,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellStringGauge1),
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewStringGauge2,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteStringGauge2,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellStringGauge2),
+]
+_bool_gauge_methods = [
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewBoolGauge0,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteBoolGauge0,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellBoolGauge0),
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewBoolGauge1,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteBoolGauge1,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellBoolGauge1),
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewBoolGauge2,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteBoolGauge2,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellBoolGauge2),
+]
+_sampler_methods = [
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewSampler0,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteSampler0,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellSampler0),
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewSampler1,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteSampler1,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellSampler1),
+    _MetricMethod(
+        create=pywrap_tensorflow.TFE_MonitoringNewSampler2,
+        delete=pywrap_tensorflow.TFE_MonitoringDeleteSampler2,
+        get_cell=pywrap_tensorflow.TFE_MonitoringGetCellSampler2),
+]
 
 
 class Metric(object):
@@ -88,7 +121,8 @@ class Metric(object):
     self._metric = self._metric_methods[self._label_length].create(*args)
 
   def __del__(self):
-    self._metric_methods[self._label_length].delete(self._metric)
+    if hasattr(self, '_metric'):
+      self._metric_methods[self._label_length].delete(self._metric)
 
   def get_cell(self, *labels):
     """Retrieves the cell."""
@@ -124,7 +158,12 @@ class CounterCell(object):
 
 
 class Counter(Metric):
-  """A stateful class for updating a cumulative integer metric."""
+  """A stateful class for updating a cumulative integer metric.
+
+  This class encapsulates a set of values (or a single value for a label-less
+  metric). Each value is identified by a tuple of labels. The class allows the
+  user to increment each value.
+  """
 
   def __init__(self, name, description, *labels):
     """Creates a new Counter.
@@ -132,7 +171,7 @@ class Counter(Metric):
     Args:
       name: name of the new metric.
       description: description of the new metric.
-      *labels: The label list of the new metrics
+      *labels: The label list of the new metric.
     """
     super(Counter, self).__init__('Counter', _counter_methods, len(labels),
                                   name, description, *labels)
@@ -140,3 +179,245 @@ class Counter(Metric):
   def get_cell(self, *labels):
     """Retrieves the cell."""
     return CounterCell(super(Counter, self).get_cell(*labels))
+
+
+class IntGaugeCell(object):
+  """A single integer value stored in an `IntGauge`."""
+
+  def __init__(self, cell):
+    """Creates a new IntGaugeCell.
+
+    Args:
+      cell: A c pointer of TFE_MonitoringIntGaugeCell.
+    """
+    self._cell = cell
+
+  def set(self, value):
+    """Atomically set the value.
+
+    Args:
+      value: integer value.
+    """
+    pywrap_tensorflow.TFE_MonitoringIntGaugeCellSet(self._cell, value)
+
+  def value(self):
+    """Retrieves the current value."""
+    return pywrap_tensorflow.TFE_MonitoringIntGaugeCellValue(self._cell)
+
+
+class IntGauge(Metric):
+  """A stateful class for updating a gauge-like integer metric.
+
+  This class encapsulates a set of integer values (or a single value for a
+  label-less metric). Each value is identified by a tuple of labels. The class
+  allows the user to set each value.
+  """
+
+  def __init__(self, name, description, *labels):
+    """Creates a new IntGauge.
+
+    Args:
+      name: name of the new metric.
+      description: description of the new metric.
+      *labels: The label list of the new metric.
+    """
+    super(IntGauge, self).__init__('IntGauge', _int_gauge_methods, len(labels),
+                                   name, description, *labels)
+
+  def get_cell(self, *labels):
+    """Retrieves the cell."""
+    return IntGaugeCell(super(IntGauge, self).get_cell(*labels))
+
+
+class StringGaugeCell(object):
+  """A single string value stored in an `StringGauge`."""
+
+  def __init__(self, cell):
+    """Creates a new StringGaugeCell.
+
+    Args:
+      cell: A c pointer of TFE_MonitoringStringGaugeCell.
+    """
+    self._cell = cell
+
+  def set(self, value):
+    """Atomically set the value.
+
+    Args:
+      value: string value.
+    """
+    pywrap_tensorflow.TFE_MonitoringStringGaugeCellSet(self._cell, value)
+
+  def value(self):
+    """Retrieves the current value."""
+    with c_api_util.tf_buffer() as buffer_:
+      pywrap_tensorflow.TFE_MonitoringStringGaugeCellValue(self._cell, buffer_)
+      value = pywrap_tensorflow.TF_GetBuffer(buffer_).decode('utf-8')
+    return value
+
+
+class StringGauge(Metric):
+  """A stateful class for updating a gauge-like string metric.
+
+  This class encapsulates a set of string values (or a single value for a
+  label-less metric). Each value is identified by a tuple of labels. The class
+  allows the user to set each value.
+  """
+
+  def __init__(self, name, description, *labels):
+    """Creates a new StringGauge.
+
+    Args:
+      name: name of the new metric.
+      description: description of the new metric.
+      *labels: The label list of the new metric.
+    """
+    super(StringGauge, self).__init__('StringGauge', _string_gauge_methods,
+                                      len(labels), name, description, *labels)
+
+  def get_cell(self, *labels):
+    """Retrieves the cell."""
+    return StringGaugeCell(super(StringGauge, self).get_cell(*labels))
+
+
+class BoolGaugeCell(object):
+  """A single boolean value stored in an `BoolGauge`."""
+
+  def __init__(self, cell):
+    """Creates a new BoolGaugeCell.
+
+    Args:
+      cell: A c pointer of TFE_MonitoringBoolGaugeCell.
+    """
+    self._cell = cell
+
+  def set(self, value):
+    """Atomically set the value.
+
+    Args:
+      value: bool value.
+    """
+    pywrap_tensorflow.TFE_MonitoringBoolGaugeCellSet(self._cell, value)
+
+  def value(self):
+    """Retrieves the current value."""
+    return pywrap_tensorflow.TFE_MonitoringBoolGaugeCellValue(self._cell)
+
+
+class BoolGauge(Metric):
+  """A stateful class for updating a gauge-like bool metric.
+
+  This class encapsulates a set of boolean values (or a single value for a
+  label-less metric). Each value is identified by a tuple of labels. The class
+  allows the user to set each value.
+  """
+
+  def __init__(self, name, description, *labels):
+    """Creates a new BoolGauge.
+
+    Args:
+      name: name of the new metric.
+      description: description of the new metric.
+      *labels: The label list of the new metric.
+    """
+    super(BoolGauge, self).__init__('BoolGauge', _bool_gauge_methods,
+                                    len(labels), name, description, *labels)
+
+  def get_cell(self, *labels):
+    """Retrieves the cell."""
+    return BoolGaugeCell(super(BoolGauge, self).get_cell(*labels))
+
+
+class SamplerCell(object):
+  """SamplerCell stores each value of a Sampler."""
+
+  def __init__(self, cell):
+    """Creates a new SamplerCell.
+
+    Args:
+      cell: A c pointer of TFE_MonitoringSamplerCell.
+    """
+    self._cell = cell
+
+  def add(self, value):
+    """Atomically add a sample.
+
+    Args:
+      value: float value.
+    """
+    pywrap_tensorflow.TFE_MonitoringSamplerCellAdd(self._cell, value)
+
+  def value(self):
+    """Retrieves the current distribution of samples.
+
+    Returns:
+      A HistogramProto describing the distribution of samples.
+    """
+    with c_api_util.tf_buffer() as buffer_:
+      pywrap_tensorflow.TFE_MonitoringSamplerCellValue(self._cell, buffer_)
+      proto_data = pywrap_tensorflow.TF_GetBuffer(buffer_)
+    histogram_proto = summary_pb2.HistogramProto()
+    histogram_proto.ParseFromString(compat.as_bytes(proto_data))
+    return histogram_proto
+
+
+class Buckets(object):
+  """Bucketing strategies for the samplers."""
+
+  def __init__(self, buckets):
+    """Creates a new Buckets.
+
+    Args:
+      buckets: A c pointer of TFE_MonitoringBuckets.
+    """
+    self.buckets = buckets
+
+  def __del__(self):
+    pywrap_tensorflow.TFE_MonitoringDeleteBuckets(self.buckets)
+
+
+class ExponentialBuckets(Buckets):
+  """Exponential bucketing strategy.
+
+  Sets up buckets of the form:
+      [-DBL_MAX, ..., scale * growth^i,
+       scale * growth_factor^(i + 1), ..., DBL_MAX].
+  """
+
+  def __init__(self, scale, growth_factor, bucket_count):
+    """Creates a new exponential Buckets.
+
+    Args:
+      scale: float
+      growth_factor: float
+      bucket_count: integer
+    """
+    super(ExponentialBuckets, self).__init__(
+        pywrap_tensorflow.TFE_MonitoringNewExponentialBuckets(
+            scale, growth_factor, bucket_count))
+
+
+class Sampler(Metric):
+  """A stateful class for updating a cumulative histogram metric.
+
+  This class encapsulates a set of histograms (or a single histogram for a
+  label-less metric) configured with a list of increasing bucket boundaries.
+  Each histogram is identified by a tuple of labels. The class allows the
+  user to add a sample to each histogram value.
+  """
+
+  def __init__(self, name, buckets, description, *labels):
+    """Creates a new Sampler.
+
+    Args:
+      name: name of the new metric.
+      buckets: bucketing strategy of the new metric.
+      description: description of the new metric.
+      *labels: The label list of the new metric.
+    """
+    super(Sampler, self).__init__('Sampler', _sampler_methods, len(labels),
+                                  name, buckets.buckets, description, *labels)
+
+  def get_cell(self, *labels):
+    """Retrieves the cell."""
+    return SamplerCell(super(Sampler, self).get_cell(*labels))
diff --git a/tensorflow/python/eager/monitoring_test.py b/tensorflow/python/eager/monitoring_test.py
index cc3ef39ba3d..3f601735ef2 100644
--- a/tensorflow/python/eager/monitoring_test.py
+++ b/tensorflow/python/eager/monitoring_test.py
@@ -26,11 +26,6 @@ from tensorflow.python.framework import test_util
 
 class MonitoringTest(test_util.TensorFlowTestCase):
 
-  def test_monitoring(self):
-    # These methods should not throw any exception.
-    monitoring.gauge('test/gauge', 'label', 1)
-    monitoring.sampler('test/sampler', 'label', 1.0)
-
   def test_counter(self):
     counter = monitoring.Counter('test/counter', 'test counter')
     counter.get_cell().increase_by(1)
@@ -52,6 +47,59 @@ class MonitoringTest(test_util.TensorFlowTestCase):
     with self.assertRaises(errors.AlreadyExistsError):
       counter2 = monitoring.Counter('test/same_counter', 'test counter')  # pylint: disable=unused-variable
 
+  def test_int_gauge(self):
+    gauge = monitoring.IntGauge('test/gauge', 'test gauge')
+    gauge.get_cell().set(1)
+    self.assertEqual(gauge.get_cell().value(), 1)
+    gauge.get_cell().set(5)
+    self.assertEqual(gauge.get_cell().value(), 5)
+
+    gauge1 = monitoring.IntGauge('test/gauge1', 'test gauge1', 'label1')
+    gauge1.get_cell('foo').set(2)
+    self.assertEqual(gauge1.get_cell('foo').value(), 2)
+
+  def test_string_gauge(self):
+    gauge = monitoring.StringGauge('test/gauge', 'test gauge')
+    gauge.get_cell().set('left')
+    self.assertEqual(gauge.get_cell().value(), 'left')
+    gauge.get_cell().set('right')
+    self.assertEqual(gauge.get_cell().value(), 'right')
+
+    gauge1 = monitoring.StringGauge('test/gauge1', 'test gauge1', 'label1')
+    gauge1.get_cell('foo').set('start')
+    self.assertEqual(gauge1.get_cell('foo').value(), 'start')
+
+  def test_bool_gauge(self):
+    gauge = monitoring.BoolGauge('test/gauge', 'test gauge')
+    gauge.get_cell().set(True)
+    self.assertTrue(gauge.get_cell().value())
+    gauge.get_cell().set(False)
+    self.assertFalse(gauge.get_cell().value())
+
+    gauge1 = monitoring.BoolGauge('test/gauge1', 'test gauge1', 'label1')
+    gauge1.get_cell('foo').set(True)
+    self.assertTrue(gauge1.get_cell('foo').value())
+
+  def test_sampler(self):
+    buckets = monitoring.ExponentialBuckets(1.0, 2.0, 2)
+    sampler = monitoring.Sampler('test/sampler', buckets, 'test sampler')
+    sampler.get_cell().add(1.0)
+    sampler.get_cell().add(5.0)
+    histogram_proto = sampler.get_cell().value()
+    self.assertEqual(histogram_proto.min, 1.0)
+    self.assertEqual(histogram_proto.num, 2.0)
+    self.assertEqual(histogram_proto.sum, 6.0)
+
+    sampler1 = monitoring.Sampler('test/sampler1', buckets, 'test sampler',
+                                  'label1')
+    sampler1.get_cell('foo').add(2.0)
+    sampler1.get_cell('foo').add(4.0)
+    sampler1.get_cell('bar').add(8.0)
+    histogram_proto1 = sampler1.get_cell('foo').value()
+    self.assertEqual(histogram_proto1.max, 4.0)
+    self.assertEqual(histogram_proto1.num, 2.0)
+    self.assertEqual(histogram_proto1.sum, 6.0)
+
 
 if __name__ == '__main__':
   test.main()
diff --git a/tensorflow/python/pywrap_tfe.i b/tensorflow/python/pywrap_tfe.i
index f3810a00f45..09cf06aea00 100755
--- a/tensorflow/python/pywrap_tfe.i
+++ b/tensorflow/python/pywrap_tfe.i
@@ -84,8 +84,6 @@ limitations under the License.
 %rename("%s") TFE_EnableCollectiveOps;
 %rename("%s") TF_ListPhysicalDevices;
 %rename("%s") TF_PickUnusedPortOrDie;
-%rename("%s") TFE_MonitoringSetGauge;
-%rename("%s") TFE_MonitoringAddSampler;
 %rename("%s") TFE_MonitoringCounterCellIncrementBy;
 %rename("%s") TFE_MonitoringCounterCellValue;
 %rename("%s") TFE_MonitoringNewCounter0;
@@ -97,6 +95,52 @@ limitations under the License.
 %rename("%s") TFE_MonitoringNewCounter2;
 %rename("%s") TFE_MonitoringDeleteCounter2;
 %rename("%s") TFE_MonitoringGetCellCounter2;
+%rename("%s") TFE_MonitoringIntGaugeCellSet;
+%rename("%s") TFE_MonitoringIntGaugeCellValue;
+%rename("%s") TFE_MonitoringNewIntGauge0;
+%rename("%s") TFE_MonitoringDeleteIntGauge0;
+%rename("%s") TFE_MonitoringGetCellIntGauge0;
+%rename("%s") TFE_MonitoringNewIntGauge1;
+%rename("%s") TFE_MonitoringDeleteIntGauge1;
+%rename("%s") TFE_MonitoringGetCellIntGauge1;
+%rename("%s") TFE_MonitoringNewIntGauge2;
+%rename("%s") TFE_MonitoringDeleteIntGauge2;
+%rename("%s") TFE_MonitoringGetCellIntGauge2;
+%rename("%s") TFE_MonitoringStringGaugeCellSet;
+%rename("%s") TFE_MonitoringStringGaugeCellValue;
+%rename("%s") TFE_MonitoringNewStringGauge0;
+%rename("%s") TFE_MonitoringDeleteStringGauge0;
+%rename("%s") TFE_MonitoringGetCellStringGauge0;
+%rename("%s") TFE_MonitoringNewStringGauge1;
+%rename("%s") TFE_MonitoringDeleteStringGauge1;
+%rename("%s") TFE_MonitoringGetCellStringGauge1;
+%rename("%s") TFE_MonitoringNewStringGauge2;
+%rename("%s") TFE_MonitoringDeleteStringGauge2;
+%rename("%s") TFE_MonitoringGetCellStringGauge2;
+%rename("%s") TFE_MonitoringBoolGaugeCellSet;
+%rename("%s") TFE_MonitoringBoolGaugeCellValue;
+%rename("%s") TFE_MonitoringNewBoolGauge0;
+%rename("%s") TFE_MonitoringDeleteBoolGauge0;
+%rename("%s") TFE_MonitoringGetCellBoolGauge0;
+%rename("%s") TFE_MonitoringNewBoolGauge1;
+%rename("%s") TFE_MonitoringDeleteBoolGauge1;
+%rename("%s") TFE_MonitoringGetCellBoolGauge1;
+%rename("%s") TFE_MonitoringNewBoolGauge2;
+%rename("%s") TFE_MonitoringDeleteBoolGauge2;
+%rename("%s") TFE_MonitoringGetCellBoolGauge2;
+%rename("%s") TFE_MonitoringSamplerCellAdd;
+%rename("%s") TFE_MonitoringSamplerCellValue;
+%rename("%s") TFE_MonitoringNewExponentialBuckets;
+%rename("%s") TFE_MonitoringDeleteBuckets;
+%rename("%s") TFE_MonitoringNewSampler0;
+%rename("%s") TFE_MonitoringDeleteSampler0;
+%rename("%s") TFE_MonitoringGetCellSampler0;
+%rename("%s") TFE_MonitoringNewSampler1;
+%rename("%s") TFE_MonitoringDeleteSampler1;
+%rename("%s") TFE_MonitoringGetCellSampler1;
+%rename("%s") TFE_MonitoringNewSampler2;
+%rename("%s") TFE_MonitoringDeleteSampler2;
+%rename("%s") TFE_MonitoringGetCellSampler2;
 
 %{
 #include "tensorflow/python/eager/pywrap_tfe.h"