From ddad8d6116e9853f836bc7f059bad75f84472377 Mon Sep 17 00:00:00 2001
From: JimmyCYJ <jimmychen.0102@gmail.com>
Date: Tue, 13 Feb 2018 15:02:35 -0800
Subject: [PATCH 1/6] Add MixerClient stats back.

---
 src/envoy/mixer/BUILD          |   2 +
 src/envoy/mixer/http_filter.cc |  16 +++++
 src/envoy/mixer/stats.cc       | 106 +++++++++++++++++++++++++++++++++
 src/envoy/mixer/stats.h        |  88 +++++++++++++++++++++++++++
 src/envoy/mixer/tcp_filter.cc  |  32 ++++++++--
 5 files changed, 238 insertions(+), 6 deletions(-)
 create mode 100644 src/envoy/mixer/stats.cc
 create mode 100644 src/envoy/mixer/stats.h

diff --git a/src/envoy/mixer/BUILD b/src/envoy/mixer/BUILD
index 055fd301661..8b3e0a086d0 100644
--- a/src/envoy/mixer/BUILD
+++ b/src/envoy/mixer/BUILD
@@ -30,6 +30,8 @@ envoy_cc_library(
         "http_filter.cc",
         "mixer_control.cc",
         "mixer_control.h",
+        "stats.cc",
+        "stats.h",
         "tcp_filter.cc",
         "utils.cc",
         "utils.h",
diff --git a/src/envoy/mixer/http_filter.cc b/src/envoy/mixer/http_filter.cc
index 36cacc29086..642ca1b7f3a 100644
--- a/src/envoy/mixer/http_filter.cc
+++ b/src/envoy/mixer/http_filter.cc
@@ -29,6 +29,7 @@
 #include "src/envoy/mixer/config.h"
 #include "src/envoy/mixer/grpc_transport.h"
 #include "src/envoy/mixer/mixer_control.h"
+#include "src/envoy/mixer/stats.h"
 #include "src/envoy/mixer/utils.h"
 
 #include <map>
@@ -36,6 +37,7 @@
 #include <thread>
 
 using ::google::protobuf::util::Status;
+using ::istio::mixer_client::Statistics;
 using HttpCheckData = ::istio::mixer_control::http::CheckData;
 using HttpHeaderUpdate = ::istio::mixer_control::http::HeaderUpdate;
 using HttpReportData = ::istio::mixer_control::http::ReportData;
@@ -54,6 +56,9 @@ const std::string kPerRouteMixer("mixer");
 // Per route opaque data name "mixer_sha" is SHA(JSON(ServiceConfig))
 const std::string kPerRouteMixerSha("mixer_sha");
 
+// Envoy stats perfix for HTTP filter stats.
+const std::string kHttpStatsPrefix("http_mixer_filter.");
+
 // The HTTP header to forward Istio attributes.
 const LowerCaseString kIstioAttributeHeader("x-istio-attributes");
 
@@ -86,6 +91,7 @@ class Config : public Logger::Loggable<Logger::Id::http> {
   Upstream::ClusterManager& cm_;
   HttpMixerConfig mixer_config_;
   ThreadLocal::SlotPtr tls_;
+  std::unique_ptr<MixerStatsObject> stats_obj_;
 
  public:
   Config(const Json::Object& config,
@@ -100,6 +106,16 @@ class Config : public Logger::Loggable<Logger::Id::http> {
               return ThreadLocal::ThreadLocalObjectSharedPtr(
                   new HttpMixerControl(mixer_config_, cm_, dispatcher, random));
             });
+    stats_obj_ = std::unique_ptr<MixerStatsObject>(new MixerStatsObject(
+        context.dispatcher(), kHttpStatsPrefix, context.scope(),
+        mixer_config_.http_config.transport().stats_update_interval(),
+        [this](Statistics* stat) -> bool {
+          if (!mixer_control().controller()) {
+            return false;
+          }
+          mixer_control().controller()->GetStatistics(stat);
+          return true;
+        }));
   }
 
   HttpMixerControl& mixer_control() {
diff --git a/src/envoy/mixer/stats.cc b/src/envoy/mixer/stats.cc
new file mode 100644
index 00000000000..7b08891c240
--- /dev/null
+++ b/src/envoy/mixer/stats.cc
@@ -0,0 +1,106 @@
+/* Copyright 2017 Istio Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+
+#include "src/envoy/mixer/stats.h"
+
+namespace Envoy {
+namespace Http {
+namespace Mixer {
+namespace {
+
+// The time interval for envoy stats update.
+const int kStatsUpdateIntervalInMs = 10000;
+
+}  // namespace
+
+MixerStatsObject::MixerStatsObject(Event::Dispatcher& dispatcher,
+                                   const std::string& name, Stats::Scope& scope,
+                                   ::google::protobuf::Duration update_interval,
+                                   GetStatsFunc func)
+    : stats_{ALL_MIXER_FILTER_STATS(POOL_COUNTER_PREFIX(scope, name))},
+      get_stats_func_(func) {
+  stats_update_interval_ = update_interval.seconds() * 1000 +
+      update_interval.nanos() / 1000000;
+  if (stats_update_interval_ <= 0) {
+    stats_update_interval_ = kStatsUpdateIntervalInMs;
+  }
+  memset(&old_stats_, 0, sizeof(old_stats_));
+
+  if (get_stats_func_) {
+    timer_ = dispatcher.createTimer([this]() { OnTimer(); });
+    timer_->enableTimer(std::chrono::milliseconds(stats_update_interval_));
+  }
+}
+
+void MixerStatsObject::OnTimer() {
+  ::istio::mixer_client::Statistics new_stats;
+  bool get_stats = get_stats_func_(&new_stats);
+  if (get_stats) {
+    CheckAndUpdateStats(new_stats);
+  }
+  timer_->enableTimer(std::chrono::milliseconds(stats_update_interval_));
+}
+
+void MixerStatsObject::CheckAndUpdateStats(
+    const ::istio::mixer_client::Statistics& new_stats) {
+  if (new_stats.total_check_calls > old_stats_.total_check_calls) {
+    stats_.total_check_calls_.add(new_stats.total_check_calls -
+                                  old_stats_.total_check_calls);
+  }
+  if (new_stats.total_remote_check_calls >
+      old_stats_.total_remote_check_calls) {
+    stats_.total_remote_check_calls_.add(new_stats.total_remote_check_calls -
+                                         old_stats_.total_remote_check_calls);
+  }
+  if (new_stats.total_blocking_remote_check_calls >
+      old_stats_.total_blocking_remote_check_calls) {
+    stats_.total_blocking_remote_check_calls_.add(
+        new_stats.total_blocking_remote_check_calls -
+        old_stats_.total_blocking_remote_check_calls);
+  }
+  if (new_stats.total_quota_calls > old_stats_.total_quota_calls) {
+    stats_.total_quota_calls_.add(new_stats.total_quota_calls -
+                                  old_stats_.total_quota_calls);
+  }
+  if (new_stats.total_remote_quota_calls >
+      old_stats_.total_remote_quota_calls) {
+    stats_.total_remote_quota_calls_.add(new_stats.total_remote_quota_calls -
+                                         old_stats_.total_remote_quota_calls);
+  }
+  if (new_stats.total_blocking_remote_quota_calls >
+      old_stats_.total_blocking_remote_quota_calls) {
+    stats_.total_blocking_remote_quota_calls_.add(
+        new_stats.total_blocking_remote_quota_calls -
+        old_stats_.total_blocking_remote_quota_calls);
+  }
+  if (new_stats.total_report_calls > old_stats_.total_report_calls) {
+    stats_.total_report_calls_.add(new_stats.total_report_calls -
+                                   old_stats_.total_report_calls);
+  }
+  if (new_stats.total_remote_report_calls >
+      old_stats_.total_remote_report_calls) {
+    stats_.total_remote_report_calls_.add(new_stats.total_remote_report_calls -
+                                          old_stats_.total_remote_report_calls);
+  }
+
+  // Copy new_stats to old_stats_ for next stats update.
+  old_stats_ = new_stats;
+}
+
+}  // namespace Mixer
+}  // namespace Http
+}  // namespace Envoy
diff --git a/src/envoy/mixer/stats.h b/src/envoy/mixer/stats.h
new file mode 100644
index 00000000000..6cbb511cda7
--- /dev/null
+++ b/src/envoy/mixer/stats.h
@@ -0,0 +1,88 @@
+/* Copyright 2017 Istio Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "envoy/event/dispatcher.h"
+#include "envoy/event/timer.h"
+#include "envoy/stats/stats_macros.h"
+#include "include/client.h"
+
+namespace Envoy {
+namespace Http {
+namespace Mixer {
+
+/**
+ * All mixer filter stats. @see stats_macros.h
+ */
+// clang-format off
+#define ALL_MIXER_FILTER_STATS(COUNTER)                                       \
+  COUNTER(total_check_calls)                                                  \
+  COUNTER(total_remote_check_calls)                                           \
+  COUNTER(total_blocking_remote_check_calls)                                  \
+  COUNTER(total_quota_calls)                                                  \
+  COUNTER(total_remote_quota_calls)                                           \
+  COUNTER(total_blocking_remote_quota_calls)                                  \
+  COUNTER(total_report_calls)                                                 \
+  COUNTER(total_remote_report_calls)
+// clang-format on
+
+/**
+ * Struct definition for all mixer filter stats. @see stats_macros.h
+ */
+struct MixerFilterStats {
+  ALL_MIXER_FILTER_STATS(GENERATE_COUNTER_STRUCT)
+};
+
+typedef std::function<bool(::istio::mixer_client::Statistics* s)> GetStatsFunc;
+
+// MixerStatsObject maintains statistics for number of check, quota and report
+// calls issued by a mixer filter.
+class MixerStatsObject {
+ public:
+  MixerStatsObject(Event::Dispatcher& dispatcher, const std::string& name,
+                   Stats::Scope& scope,
+                   ::google::protobuf::Duration update_interval,
+                   GetStatsFunc func);
+
+ private:
+  // This function is invoked when timer event fires.
+  void OnTimer();
+
+  // Compares old stats with new stats and updates envoy stats.
+  void CheckAndUpdateStats(const ::istio::mixer_client::Statistics& new_stats);
+
+  // A set of Envoy stats for the number of check, quota and report calls.
+  MixerFilterStats stats_;
+  // Stores a function which gets statistics from mixer controller.
+  GetStatsFunc get_stats_func_;
+
+  // stats from last call to get_stats_func_. This is needed to calculate the
+  // variances of stats and update envoy stats.
+  ::istio::mixer_client::Statistics old_stats_;
+
+  // These members are used for creating a timer which update Envoy stats
+  // periodically.
+  ::Envoy::Event::TimerPtr timer_;
+
+  // Time interval at which Envoy stats get updated. If stats update interval
+  // from config is larger than 0, then store configured interval here.
+  // Otherwise, set interval to 10 seconds.
+  int stats_update_interval_;
+};
+
+}  // namespace Mixer
+}  // namespace Http
+}  // namespace Envoy
diff --git a/src/envoy/mixer/tcp_filter.cc b/src/envoy/mixer/tcp_filter.cc
index 837426c5746..74a878f55bc 100644
--- a/src/envoy/mixer/tcp_filter.cc
+++ b/src/envoy/mixer/tcp_filter.cc
@@ -22,20 +22,29 @@
 #include "server/config/network/http_connection_manager.h"
 #include "src/envoy/mixer/config.h"
 #include "src/envoy/mixer/mixer_control.h"
+#include "src/envoy/mixer/stats.h"
 #include "src/envoy/mixer/utils.h"
 
 using ::google::protobuf::util::Status;
 using StatusCode = ::google::protobuf::util::error::Code;
+using ::istio::mixer_client::Statistics;
 
 namespace Envoy {
 namespace Http {
 namespace Mixer {
+namespace {
+
+// Envoy stats perfix for TCP filter stats.
+const std::string kTcpStatsPrefix("tcp_mixer_filter.");
+
+}  // namespace
 
 class TcpConfig : public Logger::Loggable<Logger::Id::filter> {
  private:
   Upstream::ClusterManager& cm_;
   TcpMixerConfig mixer_config_;
   ThreadLocal::SlotPtr tls_;
+  std::unique_ptr<MixerStatsObject> stats_obj_;
 
  public:
   TcpConfig(const Json::Object& config,
@@ -44,12 +53,23 @@ class TcpConfig : public Logger::Loggable<Logger::Id::filter> {
         tls_(context.threadLocal().allocateSlot()) {
     mixer_config_.Load(config);
     Runtime::RandomGenerator& random = context.random();
-    tls_->set(
-        [this, &random](Event::Dispatcher& dispatcher)
-            -> ThreadLocal::ThreadLocalObjectSharedPtr {
-              return ThreadLocal::ThreadLocalObjectSharedPtr(
-                  new TcpMixerControl(mixer_config_, cm_, dispatcher, random));
-            });
+    Stats::Scope& scope = context.scope();
+    tls_->set([this, &random, &scope](Event::Dispatcher& dispatcher)
+                  -> ThreadLocal::ThreadLocalObjectSharedPtr {
+                    return ThreadLocal::ThreadLocalObjectSharedPtr(
+                        new TcpMixerControl(mixer_config_, cm_, dispatcher,
+                                            random));
+                  });
+    stats_obj_ = std::unique_ptr<MixerStatsObject>(new MixerStatsObject(
+        context.dispatcher(), kTcpStatsPrefix, context.scope(),
+        mixer_config_.tcp_config.transport().stats_update_interval(),
+        [this](Statistics* stat) -> bool {
+          if (!mixer_control().controller()) {
+            return false;
+          }
+          mixer_control().controller()->GetStatistics(stat);
+          return true;
+        }));
   }
 
   TcpMixerControl& mixer_control() { return tls_->getTyped<TcpMixerControl>(); }

From 5b92a863046c8bc5adeb1973455f8d30e260ca50 Mon Sep 17 00:00:00 2001
From: JimmyCYJ <jimmychen.0102@gmail.com>
Date: Tue, 13 Feb 2018 15:03:30 -0800
Subject: [PATCH 2/6] Fix format.

---
 src/envoy/mixer/stats.cc      |  4 ++--
 src/envoy/mixer/tcp_filter.cc | 12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/envoy/mixer/stats.cc b/src/envoy/mixer/stats.cc
index 7b08891c240..a798458d2d3 100644
--- a/src/envoy/mixer/stats.cc
+++ b/src/envoy/mixer/stats.cc
@@ -33,8 +33,8 @@ MixerStatsObject::MixerStatsObject(Event::Dispatcher& dispatcher,
                                    GetStatsFunc func)
     : stats_{ALL_MIXER_FILTER_STATS(POOL_COUNTER_PREFIX(scope, name))},
       get_stats_func_(func) {
-  stats_update_interval_ = update_interval.seconds() * 1000 +
-      update_interval.nanos() / 1000000;
+  stats_update_interval_ =
+      update_interval.seconds() * 1000 + update_interval.nanos() / 1000000;
   if (stats_update_interval_ <= 0) {
     stats_update_interval_ = kStatsUpdateIntervalInMs;
   }
diff --git a/src/envoy/mixer/tcp_filter.cc b/src/envoy/mixer/tcp_filter.cc
index 74a878f55bc..751bff8f8ba 100644
--- a/src/envoy/mixer/tcp_filter.cc
+++ b/src/envoy/mixer/tcp_filter.cc
@@ -54,12 +54,12 @@ class TcpConfig : public Logger::Loggable<Logger::Id::filter> {
     mixer_config_.Load(config);
     Runtime::RandomGenerator& random = context.random();
     Stats::Scope& scope = context.scope();
-    tls_->set([this, &random, &scope](Event::Dispatcher& dispatcher)
-                  -> ThreadLocal::ThreadLocalObjectSharedPtr {
-                    return ThreadLocal::ThreadLocalObjectSharedPtr(
-                        new TcpMixerControl(mixer_config_, cm_, dispatcher,
-                                            random));
-                  });
+    tls_->set(
+        [this, &random, &scope](Event::Dispatcher& dispatcher)
+            -> ThreadLocal::ThreadLocalObjectSharedPtr {
+              return ThreadLocal::ThreadLocalObjectSharedPtr(
+                  new TcpMixerControl(mixer_config_, cm_, dispatcher, random));
+            });
     stats_obj_ = std::unique_ptr<MixerStatsObject>(new MixerStatsObject(
         context.dispatcher(), kTcpStatsPrefix, context.scope(),
         mixer_config_.tcp_config.transport().stats_update_interval(),

From 26b6eddf371617af6f918a4cc098eb4eafce8ab6 Mon Sep 17 00:00:00 2001
From: JimmyCYJ <jimmychen.0102@gmail.com>
Date: Tue, 13 Feb 2018 16:16:31 -0800
Subject: [PATCH 3/6] Create Envoy stats in filter config.

---
 src/envoy/mixer/http_filter.cc   | 34 ++++++++++++--------------------
 src/envoy/mixer/mixer_control.cc | 34 ++++++++++++++++++++++++++++----
 src/envoy/mixer/mixer_control.h  |  9 +++++++--
 src/envoy/mixer/stats.cc         |  6 ++----
 src/envoy/mixer/stats.h          |  5 ++---
 src/envoy/mixer/tcp_filter.cc    | 29 ++++++++++-----------------
 6 files changed, 64 insertions(+), 53 deletions(-)

diff --git a/src/envoy/mixer/http_filter.cc b/src/envoy/mixer/http_filter.cc
index 642ca1b7f3a..aede8301c68 100644
--- a/src/envoy/mixer/http_filter.cc
+++ b/src/envoy/mixer/http_filter.cc
@@ -56,15 +56,15 @@ const std::string kPerRouteMixer("mixer");
 // Per route opaque data name "mixer_sha" is SHA(JSON(ServiceConfig))
 const std::string kPerRouteMixerSha("mixer_sha");
 
-// Envoy stats perfix for HTTP filter stats.
-const std::string kHttpStatsPrefix("http_mixer_filter.");
-
 // The HTTP header to forward Istio attributes.
 const LowerCaseString kIstioAttributeHeader("x-istio-attributes");
 
 // Referer header
 const LowerCaseString kRefererHeaderKey("referer");
 
+// Envoy stats perfix for HTTP filter stats.
+const std::string kHttpStatsPrefix("http_mixer_filter.");
+
 // Set of headers excluded from request.headers attribute.
 const std::set<std::string> RequestHeaderExclusives = {
     kIstioAttributeHeader.get(),
@@ -91,31 +91,23 @@ class Config : public Logger::Loggable<Logger::Id::http> {
   Upstream::ClusterManager& cm_;
   HttpMixerConfig mixer_config_;
   ThreadLocal::SlotPtr tls_;
-  std::unique_ptr<MixerStatsObject> stats_obj_;
+  MixerFilterStats stats_;
 
  public:
   Config(const Json::Object& config,
          Server::Configuration::FactoryContext& context)
       : cm_(context.clusterManager()),
-        tls_(context.threadLocal().allocateSlot()) {
+        tls_(context.threadLocal().allocateSlot()),
+        stats_{ALL_MIXER_FILTER_STATS(
+            POOL_COUNTER_PREFIX(context.scope(), kHttpStatsPrefix))} {
     mixer_config_.Load(config);
     Runtime::RandomGenerator& random = context.random();
-    tls_->set(
-        [this, &random](Event::Dispatcher& dispatcher)
-            -> ThreadLocal::ThreadLocalObjectSharedPtr {
-              return ThreadLocal::ThreadLocalObjectSharedPtr(
-                  new HttpMixerControl(mixer_config_, cm_, dispatcher, random));
-            });
-    stats_obj_ = std::unique_ptr<MixerStatsObject>(new MixerStatsObject(
-        context.dispatcher(), kHttpStatsPrefix, context.scope(),
-        mixer_config_.http_config.transport().stats_update_interval(),
-        [this](Statistics* stat) -> bool {
-          if (!mixer_control().controller()) {
-            return false;
-          }
-          mixer_control().controller()->GetStatistics(stat);
-          return true;
-        }));
+    tls_->set([this, &random](Event::Dispatcher& dispatcher)
+                  -> ThreadLocal::ThreadLocalObjectSharedPtr {
+                    return ThreadLocal::ThreadLocalObjectSharedPtr(
+                        new HttpMixerControl(mixer_config_, cm_, dispatcher,
+                                             random, stats_));
+                  });
   }
 
   HttpMixerControl& mixer_control() {
diff --git a/src/envoy/mixer/mixer_control.cc b/src/envoy/mixer/mixer_control.cc
index ce62f509b86..8bc3ada503b 100644
--- a/src/envoy/mixer/mixer_control.cc
+++ b/src/envoy/mixer/mixer_control.cc
@@ -15,6 +15,8 @@
 
 #include "src/envoy/mixer/mixer_control.h"
 
+using ::istio::mixer_client::Statistics;
+
 namespace Envoy {
 namespace Http {
 namespace Mixer {
@@ -66,8 +68,20 @@ void CreateEnvironment(Upstream::ClusterManager& cm,
 HttpMixerControl::HttpMixerControl(const HttpMixerConfig& mixer_config,
                                    Upstream::ClusterManager& cm,
                                    Event::Dispatcher& dispatcher,
-                                   Runtime::RandomGenerator& random)
-    : config_(mixer_config), cm_(cm) {
+                                   Runtime::RandomGenerator& random,
+                                   MixerFilterStats& stats)
+    : config_(mixer_config),
+      cm_(cm),
+      stats_obj_(dispatcher,
+                 mixer_config.http_config.transport().stats_update_interval(),
+                 [this](Statistics* stat) -> bool {
+                   if (!controller_) {
+                     return false;
+                   }
+                   controller_->GetStatistics(stat);
+                   return true;
+                 },
+                 stats) {
   ::istio::mixer_control::http::Controller::Options options(
       mixer_config.http_config);
 
@@ -80,8 +94,20 @@ HttpMixerControl::HttpMixerControl(const HttpMixerConfig& mixer_config,
 TcpMixerControl::TcpMixerControl(const TcpMixerConfig& mixer_config,
                                  Upstream::ClusterManager& cm,
                                  Event::Dispatcher& dispatcher,
-                                 Runtime::RandomGenerator& random)
-    : config_(mixer_config), dispatcher_(dispatcher) {
+                                 Runtime::RandomGenerator& random,
+                                 MixerFilterStats& stats)
+    : config_(mixer_config),
+      dispatcher_(dispatcher),
+      stats_obj_(dispatcher,
+                 mixer_config.tcp_config.transport().stats_update_interval(),
+                 [this](Statistics* stat) -> bool {
+                   if (!controller_) {
+                     return false;
+                   }
+                   controller_->GetStatistics(stat);
+                   return true;
+                 },
+                 stats) {
   ::istio::mixer_control::tcp::Controller::Options options(
       mixer_config.tcp_config);
 
diff --git a/src/envoy/mixer/mixer_control.h b/src/envoy/mixer/mixer_control.h
index 27dbd8fe411..619636450c1 100644
--- a/src/envoy/mixer/mixer_control.h
+++ b/src/envoy/mixer/mixer_control.h
@@ -23,6 +23,7 @@
 #include "envoy/upstream/cluster_manager.h"
 #include "src/envoy/mixer/config.h"
 #include "src/envoy/mixer/grpc_transport.h"
+#include "src/envoy/mixer/stats.h"
 
 namespace Envoy {
 namespace Http {
@@ -33,7 +34,7 @@ class HttpMixerControl final : public ThreadLocal::ThreadLocalObject {
   // The constructor.
   HttpMixerControl(const HttpMixerConfig& mixer_config,
                    Upstream::ClusterManager& cm, Event::Dispatcher& dispatcher,
-                   Runtime::RandomGenerator& random);
+                   Runtime::RandomGenerator& random, MixerFilterStats& stats);
 
   ::istio::mixer_control::http::Controller* controller() {
     return controller_.get();
@@ -50,6 +51,8 @@ class HttpMixerControl final : public ThreadLocal::ThreadLocalObject {
   Upstream::ClusterManager& cm_;
   // The mixer control
   std::unique_ptr<::istio::mixer_control::http::Controller> controller_;
+
+  MixerStatsObject stats_obj_;
 };
 
 class TcpMixerControl final : public ThreadLocal::ThreadLocalObject {
@@ -57,7 +60,7 @@ class TcpMixerControl final : public ThreadLocal::ThreadLocalObject {
   // The constructor.
   TcpMixerControl(const TcpMixerConfig& mixer_config,
                   Upstream::ClusterManager& cm, Event::Dispatcher& dispatcher,
-                  Runtime::RandomGenerator& random);
+                  Runtime::RandomGenerator& random, MixerFilterStats& stats);
 
   ::istio::mixer_control::tcp::Controller* controller() {
     return controller_.get();
@@ -79,6 +82,8 @@ class TcpMixerControl final : public ThreadLocal::ThreadLocalObject {
   std::chrono::milliseconds report_interval_ms_;
 
   Event::Dispatcher& dispatcher_;
+
+  MixerStatsObject stats_obj_;
 };
 
 }  // namespace Mixer
diff --git a/src/envoy/mixer/stats.cc b/src/envoy/mixer/stats.cc
index a798458d2d3..8b3017093b7 100644
--- a/src/envoy/mixer/stats.cc
+++ b/src/envoy/mixer/stats.cc
@@ -28,11 +28,9 @@ const int kStatsUpdateIntervalInMs = 10000;
 }  // namespace
 
 MixerStatsObject::MixerStatsObject(Event::Dispatcher& dispatcher,
-                                   const std::string& name, Stats::Scope& scope,
                                    ::google::protobuf::Duration update_interval,
-                                   GetStatsFunc func)
-    : stats_{ALL_MIXER_FILTER_STATS(POOL_COUNTER_PREFIX(scope, name))},
-      get_stats_func_(func) {
+                                   GetStatsFunc func, MixerFilterStats& stats)
+    : stats_(stats), get_stats_func_(func) {
   stats_update_interval_ =
       update_interval.seconds() * 1000 + update_interval.nanos() / 1000000;
   if (stats_update_interval_ <= 0) {
diff --git a/src/envoy/mixer/stats.h b/src/envoy/mixer/stats.h
index 6cbb511cda7..13846580b4c 100644
--- a/src/envoy/mixer/stats.h
+++ b/src/envoy/mixer/stats.h
@@ -52,10 +52,9 @@ typedef std::function<bool(::istio::mixer_client::Statistics* s)> GetStatsFunc;
 // calls issued by a mixer filter.
 class MixerStatsObject {
  public:
-  MixerStatsObject(Event::Dispatcher& dispatcher, const std::string& name,
-                   Stats::Scope& scope,
+  MixerStatsObject(Event::Dispatcher& dispatcher,
                    ::google::protobuf::Duration update_interval,
-                   GetStatsFunc func);
+                   GetStatsFunc func, MixerFilterStats& stats);
 
  private:
   // This function is invoked when timer event fires.
diff --git a/src/envoy/mixer/tcp_filter.cc b/src/envoy/mixer/tcp_filter.cc
index 751bff8f8ba..7b8410aa8f4 100644
--- a/src/envoy/mixer/tcp_filter.cc
+++ b/src/envoy/mixer/tcp_filter.cc
@@ -44,32 +44,23 @@ class TcpConfig : public Logger::Loggable<Logger::Id::filter> {
   Upstream::ClusterManager& cm_;
   TcpMixerConfig mixer_config_;
   ThreadLocal::SlotPtr tls_;
-  std::unique_ptr<MixerStatsObject> stats_obj_;
+  MixerFilterStats stats_;
 
  public:
   TcpConfig(const Json::Object& config,
             Server::Configuration::FactoryContext& context)
       : cm_(context.clusterManager()),
-        tls_(context.threadLocal().allocateSlot()) {
+        tls_(context.threadLocal().allocateSlot()),
+        stats_{ALL_MIXER_FILTER_STATS(
+            POOL_COUNTER_PREFIX(context.scope(), kTcpStatsPrefix))} {
     mixer_config_.Load(config);
     Runtime::RandomGenerator& random = context.random();
-    Stats::Scope& scope = context.scope();
-    tls_->set(
-        [this, &random, &scope](Event::Dispatcher& dispatcher)
-            -> ThreadLocal::ThreadLocalObjectSharedPtr {
-              return ThreadLocal::ThreadLocalObjectSharedPtr(
-                  new TcpMixerControl(mixer_config_, cm_, dispatcher, random));
-            });
-    stats_obj_ = std::unique_ptr<MixerStatsObject>(new MixerStatsObject(
-        context.dispatcher(), kTcpStatsPrefix, context.scope(),
-        mixer_config_.tcp_config.transport().stats_update_interval(),
-        [this](Statistics* stat) -> bool {
-          if (!mixer_control().controller()) {
-            return false;
-          }
-          mixer_control().controller()->GetStatistics(stat);
-          return true;
-        }));
+    tls_->set([this, &random](Event::Dispatcher& dispatcher)
+                  -> ThreadLocal::ThreadLocalObjectSharedPtr {
+                    return ThreadLocal::ThreadLocalObjectSharedPtr(
+                        new TcpMixerControl(mixer_config_, cm_, dispatcher,
+                                            random, stats_));
+                  });
   }
 
   TcpMixerControl& mixer_control() { return tls_->getTyped<TcpMixerControl>(); }

From c7bf72b37b19124a6406bbccd49da199c55fabac Mon Sep 17 00:00:00 2001
From: JimmyCYJ <jimmychen.0102@gmail.com>
Date: Wed, 14 Feb 2018 11:25:04 -0800
Subject: [PATCH 4/6] Revise per comment.

---
 src/envoy/mixer/mixer_control.cc | 16 +++++++---------
 src/envoy/mixer/stats.cc         |  3 ++-
 src/envoy/mixer/stats.h          |  4 ++--
 3 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/src/envoy/mixer/mixer_control.cc b/src/envoy/mixer/mixer_control.cc
index 8bc3ada503b..ef2fac85264 100644
--- a/src/envoy/mixer/mixer_control.cc
+++ b/src/envoy/mixer/mixer_control.cc
@@ -54,9 +54,9 @@ void CreateEnvironment(Upstream::ClusterManager& cm,
 
   env->timer_create_func = [&dispatcher](std::function<void()> timer_cb)
       -> std::unique_ptr<::istio::mixer_client::Timer> {
-        return std::unique_ptr<::istio::mixer_client::Timer>(
-            new EnvoyTimer(dispatcher.createTimer(timer_cb)));
-      };
+    return std::unique_ptr<::istio::mixer_client::Timer>(
+        new EnvoyTimer(dispatcher.createTimer(timer_cb)));
+  };
 
   env->uuid_generate_func = [&random]() -> std::string {
     return random.uuid();
@@ -72,7 +72,7 @@ HttpMixerControl::HttpMixerControl(const HttpMixerConfig& mixer_config,
                                    MixerFilterStats& stats)
     : config_(mixer_config),
       cm_(cm),
-      stats_obj_(dispatcher,
+      stats_obj_(dispatcher, stats,
                  mixer_config.http_config.transport().stats_update_interval(),
                  [this](Statistics* stat) -> bool {
                    if (!controller_) {
@@ -80,8 +80,7 @@ HttpMixerControl::HttpMixerControl(const HttpMixerConfig& mixer_config,
                    }
                    controller_->GetStatistics(stat);
                    return true;
-                 },
-                 stats) {
+                 }) {
   ::istio::mixer_control::http::Controller::Options options(
       mixer_config.http_config);
 
@@ -98,7 +97,7 @@ TcpMixerControl::TcpMixerControl(const TcpMixerConfig& mixer_config,
                                  MixerFilterStats& stats)
     : config_(mixer_config),
       dispatcher_(dispatcher),
-      stats_obj_(dispatcher,
+      stats_obj_(dispatcher, stats,
                  mixer_config.tcp_config.transport().stats_update_interval(),
                  [this](Statistics* stat) -> bool {
                    if (!controller_) {
@@ -106,8 +105,7 @@ TcpMixerControl::TcpMixerControl(const TcpMixerConfig& mixer_config,
                    }
                    controller_->GetStatistics(stat);
                    return true;
-                 },
-                 stats) {
+                 }) {
   ::istio::mixer_control::tcp::Controller::Options options(
       mixer_config.tcp_config);
 
diff --git a/src/envoy/mixer/stats.cc b/src/envoy/mixer/stats.cc
index 8b3017093b7..2500aa053fd 100644
--- a/src/envoy/mixer/stats.cc
+++ b/src/envoy/mixer/stats.cc
@@ -28,8 +28,9 @@ const int kStatsUpdateIntervalInMs = 10000;
 }  // namespace
 
 MixerStatsObject::MixerStatsObject(Event::Dispatcher& dispatcher,
+                                   MixerFilterStats& stats,
                                    ::google::protobuf::Duration update_interval,
-                                   GetStatsFunc func, MixerFilterStats& stats)
+                                   GetStatsFunc func)
     : stats_(stats), get_stats_func_(func) {
   stats_update_interval_ =
       update_interval.seconds() * 1000 + update_interval.nanos() / 1000000;
diff --git a/src/envoy/mixer/stats.h b/src/envoy/mixer/stats.h
index 13846580b4c..0992c50801a 100644
--- a/src/envoy/mixer/stats.h
+++ b/src/envoy/mixer/stats.h
@@ -52,9 +52,9 @@ typedef std::function<bool(::istio::mixer_client::Statistics* s)> GetStatsFunc;
 // calls issued by a mixer filter.
 class MixerStatsObject {
  public:
-  MixerStatsObject(Event::Dispatcher& dispatcher,
+  MixerStatsObject(Event::Dispatcher& dispatcher, MixerFilterStats& stats,
                    ::google::protobuf::Duration update_interval,
-                   GetStatsFunc func, MixerFilterStats& stats);
+                   GetStatsFunc func);
 
  private:
   // This function is invoked when timer event fires.

From 0fef9ddea113c10659f606248547684183c68357 Mon Sep 17 00:00:00 2001
From: JimmyCYJ <jimmychen.0102@gmail.com>
Date: Wed, 14 Feb 2018 11:31:56 -0800
Subject: [PATCH 5/6] Fix format.

---
 src/envoy/mixer/mixer_control.cc | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/envoy/mixer/mixer_control.cc b/src/envoy/mixer/mixer_control.cc
index ef2fac85264..9f207de7206 100644
--- a/src/envoy/mixer/mixer_control.cc
+++ b/src/envoy/mixer/mixer_control.cc
@@ -54,9 +54,9 @@ void CreateEnvironment(Upstream::ClusterManager& cm,
 
   env->timer_create_func = [&dispatcher](std::function<void()> timer_cb)
       -> std::unique_ptr<::istio::mixer_client::Timer> {
-    return std::unique_ptr<::istio::mixer_client::Timer>(
-        new EnvoyTimer(dispatcher.createTimer(timer_cb)));
-  };
+        return std::unique_ptr<::istio::mixer_client::Timer>(
+            new EnvoyTimer(dispatcher.createTimer(timer_cb)));
+      };
 
   env->uuid_generate_func = [&random]() -> std::string {
     return random.uuid();

From 421faf138afa818b3819984a57d87e0e900ba46d Mon Sep 17 00:00:00 2001
From: JimmyCYJ <jimmychen.0102@gmail.com>
Date: Wed, 14 Feb 2018 11:45:10 -0800
Subject: [PATCH 6/6] Revise per comment.

---
 src/envoy/mixer/stats.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/envoy/mixer/stats.h b/src/envoy/mixer/stats.h
index 0992c50801a..3e1f403235c 100644
--- a/src/envoy/mixer/stats.h
+++ b/src/envoy/mixer/stats.h
@@ -64,7 +64,7 @@ class MixerStatsObject {
   void CheckAndUpdateStats(const ::istio::mixer_client::Statistics& new_stats);
 
   // A set of Envoy stats for the number of check, quota and report calls.
-  MixerFilterStats stats_;
+  MixerFilterStats& stats_;
   // Stores a function which gets statistics from mixer controller.
   GetStatsFunc get_stats_func_;
 
