Merge pull request #2 from crystaldust/docs/istio-as-controlplane

Add docs to use Istio as control plane.
diff --git a/.gitignore b/.gitignore
index 6a5366d..e50b616 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,4 +28,4 @@
 
 _build
 coverage.txt
-go.sum
\ No newline at end of file
+go.sum
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..4f90ccd
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,49 @@
+language: go
+sudo: required
+go:
+  - 1.11
+install: true
+
+before_script:
+  - mkdir -p $HOME/gopath/src/github.com/go-mesh/mesher
+  - rsync -az ${TRAVIS_BUILD_DIR}/ $HOME/gopath/src/github.com/go-mesh/mesher
+  - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/go-mesh/mesher
+  - export KUBE_CONFIG=$HOME/gopath/src/github.com/go-mesh/mesher/vendor/github.com/go-mesh/mesher-tools/test/util/sample_kubeconfig
+  - cd $HOME/gopath/src/github.com/go-mesh/mesher
+jobs:
+  include:
+    - stage: Format Checker
+      script: bash -x scripts/travis/formatChecker.sh
+    - stage: DeadCode Checker
+      script:
+        - go get -u github.com/tsenart/deadcode
+        - bash -x scripts/travis/deadCodeChecker.sh
+    - stage: Misspell Checker
+      script:
+        - go get -u github.com/client9/misspell
+        - bash -x scripts/travis/misspellChecker.sh
+    - stage: GoConst Checker
+      script:
+        - go get -u github.com/jgautheron/goconst/cmd/goconst
+        - bash -x scripts/travis/goConstChecker.sh
+    - stage: GoLint Checker
+      script:
+        - go get -u github.com/golang/lint/golint
+        - bash -x scripts/travis/goLintChecker.sh
+    - stage: GoCyclo Checker
+      script:
+        - go get github.com/fzipp/gocyclo
+        - bash -x scripts/travis/goCycloChecker.sh
+    - stage: Build
+      script: 
+        - GO111MODULE=on go mod download
+        - GO111MODULE=on go mod vendor
+        - go build
+    - stage: Unit Test
+      script:
+        - go get github.com/mattn/goveralls
+        - go get golang.org/x/tools/cmd/cover
+        - GO111MODULE=on go mod download
+        - GO111MODULE=on go mod vendor
+        - bash -x scripts/travis/unit_test.sh && $HOME/gopath/bin/goveralls -coverprofile=coverage.txt -service=travis-ci
+
diff --git a/README.md b/README.md
index 3519ed0..ab9f9ea 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Mesher
 
-[![Build Status](https://travis-ci.org/go-chassis/mesher.svg?branch=master)](https://travis-ci.org/go-chassis/mesher) [![Coverage Status](https://coveralls.io/repos/github/go-chassis/mesher/badge.svg?branch=master)](https://coveralls.io/github/go-chassis/mesher?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/go-chassis/mesher)](https://goreportcard.com/report/github.com/go-chassis/mesher) [![GoDoc](https://godoc.org/github.com/go-chassis/mesher?status.svg)](https://godoc.org/github.com/go-chassis/mesher) [![HitCount](http://hits.dwyl.io/go-chassis/mesher.svg)](http://hits.dwyl.io/go-chassis/mesher) [![Join Slack](https://img.shields.io/badge/Join-Slack-orange.svg)](https://join.slack.com/t/go-chassis/shared_invite/enQtMzk0MzAyMjEzNzEyLTRjOWE3NzNmN2IzOGZhMzZkZDFjODM1MDc5ZWI0YjcxYjM1ODNkY2RkNmIxZDdlOWI3NmQ0MTg3NzBkNGExZGU)
+[![Build Status](https://travis-ci.org/go-mesh/mesher.svg?branch=master)](https://travis-ci.org/go-mesh/mesher) [![Coverage Status](https://coveralls.io/repos/github/go-mesh/mesher/badge.svg?branch=master)](https://coveralls.io/github/go-mesh/mesher?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/go-mesh/mesher)](https://goreportcard.com/report/github.com/go-mesh/mesher) [![GoDoc](https://godoc.org/github.com/go-mesh/mesher?status.svg)](https://godoc.org/github.com/go-mesh/mesher) [![HitCount](http://hits.dwyl.io/go-mesh/mesher.svg)](http://hits.dwyl.io/go-mesh/mesher) [![Join Slack](https://img.shields.io/badge/Join-Slack-orange.svg)](https://join.slack.com/t/go-chassis/shared_invite/enQtMzk0MzAyMjEzNzEyLTRjOWE3NzNmN2IzOGZhMzZkZDFjODM1MDc5ZWI0YjcxYjM1ODNkY2RkNmIxZDdlOWI3NmQ0MTg3NzBkNGExZGU)
 
 A service mesh implementation based on [go chassis](https://github.com/go-chassis/go-chassis).
 
@@ -20,7 +20,7 @@
 
 
 # Get started
-Refer to [mesher-examples](https://github.com/go-chassis/mesher-examples)
+Refer to [mesher-examples](https://github.com/go-mesh/mesher-examples)
 
 ### How to build and run
 
diff --git a/adminapi/adminService.go b/adminapi/adminService.go
index deaa53d..9fd8dea 100644
--- a/adminapi/adminService.go
+++ b/adminapi/adminService.go
@@ -25,6 +25,5 @@
 
 //RegisterWebService creates route and returns all admin api's
 func RegisterWebService() {
-
 	chassis.RegisterSchema("rest-admin", &Admin{})
 }
diff --git a/adminapi/router.go b/adminapi/router.go
index d007553..fcf808f 100644
--- a/adminapi/router.go
+++ b/adminapi/router.go
@@ -26,22 +26,20 @@
 	chassisTLS "github.com/go-chassis/go-chassis/core/tls"
 	"github.com/go-mesh/mesher/common"
 	"github.com/go-mesh/mesher/config"
-	"github.com/go-mesh/mesher/metrics"
+	"github.com/go-mesh/openlogging"
 )
 
 //Init function initiates admin server config and runs it
 func Init() (err error) {
 	isAdminEnable := config.GetConfig().Admin.Enable
 
-	if isAdminEnable != nil && *isAdminEnable == false {
+	if !isAdminEnable {
 		lager.Logger.Infof("admin api are not enable")
 		return nil
 	}
 
-	metrics.Init()
-	go func() {
-		RegisterWebService()
-	}()
+	openlogging.GetLogger().Info("enable admin API")
+	RegisterWebService()
 	return
 }
 
diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go
index a5563a7..2c2c516 100644
--- a/bootstrap/bootstrap.go
+++ b/bootstrap/bootstrap.go
@@ -33,6 +33,8 @@
 	chassisHandler "github.com/go-chassis/go-chassis/core/handler"
 	"github.com/go-chassis/go-chassis/core/lager"
 	"github.com/go-chassis/go-chassis/core/metadata"
+	"github.com/go-mesh/mesher/pkg/metrics"
+	"github.com/go-mesh/mesher/pkg/runtime"
 )
 
 // Start initialize configs and components
@@ -49,6 +51,7 @@
 	if err := DecideMode(); err != nil {
 		return err
 	}
+	metrics.Init()
 	if err := adminapi.Init(); err != nil {
 		log.Println("Error occurred in starting admin server", err)
 	}
@@ -65,8 +68,8 @@
 
 //DecideMode get config mode
 func DecideMode() error {
-	config.Mode = cmd.Configs.Mode
-	lager.Logger.Info("Running as "+config.Mode, nil)
+	runtime.Mode = cmd.Configs.Mode
+	lager.Logger.Info("Running as "+runtime.Mode, nil)
 	return nil
 }
 
@@ -109,6 +112,7 @@
 	}
 	providerChainMap := map[string]string{
 		common.ChainProviderIncoming: providerChain,
+		"default":                    chassisHandler.RatelimiterProvider,
 	}
 	chassis.SetDefaultConsumerChains(consumerChainMap)
 	chassis.SetDefaultProviderChains(providerChainMap)
diff --git a/conf/chassis.yaml b/conf/chassis.yaml
index 6858121..c0a03ac 100644
--- a/conf/chassis.yaml
+++ b/conf/chassis.yaml
@@ -6,7 +6,7 @@
     http:
       listenAddress: 127.0.0.1:30101
     rest-admin:
-      listenAddress: 0.0.0.0:30102 # listen addr use to adminAPI
+      listenAddress: 127.0.0.1:30102 # listen addr use to adminAPI
   service:
     registry:
       address: http://127.0.0.1:30100 # uri of service center
diff --git a/conf/mesher.yaml b/conf/mesher.yaml
index 0355e3e..f812844 100644
--- a/conf/mesher.yaml
+++ b/conf/mesher.yaml
@@ -3,8 +3,9 @@
 #  destinationResolver:
 #    http: host # how to turn host to destination name. default to service name,
 
-##admin: #admin API
-#  goRuntimeMetrics : true # enable metrics
+admin: #admin API
+  goRuntimeMetrics : true # enable metrics
+  enable: true
 
 ## enable pprof to profile mesher runtime
 #pprof:
diff --git a/config/config.go b/config/config.go
index 915c361..14f6cd5 100644
--- a/config/config.go
+++ b/config/config.go
@@ -37,8 +37,6 @@
 	ConfFile = "mesher.yaml"
 )
 
-//Mode is of type string which gives mode of mesher deployment
-var Mode string
 var mesherConfig *MesherConfig
 
 //GetConfig returns mesher config
diff --git a/config/struct.go b/config/struct.go
index 59c9852..e36e6aa 100644
--- a/config/struct.go
+++ b/config/struct.go
@@ -45,7 +45,7 @@
 
 //Admin has attributes for enabling, serverURI and metrics for admin data
 type Admin struct {
-	Enable           *bool  `yaml:"enable"`
+	Enable           bool   `yaml:"enable"`
 	ServerURI        string `yaml:"serverUri"`
 	GoRuntimeMetrics bool   `yaml:"goRuntimeMetrics"`
 }
diff --git a/docs/getstarted/install.md b/docs/getstarted/install.md
index 4eed0d0..22dd962 100644
--- a/docs/getstarted/install.md
+++ b/docs/getstarted/install.md
@@ -40,7 +40,7 @@
 ### Run on different infrastructure
 
 Mesher does not bind to any platform or infrastructures, plz refer to 
-https://github.com/go-chassis/mesher-examples/tree/master/Infrastructure
+https://github.com/go-mesh/mesher-examples/tree/master/Infrastructure
 to know how to run mesher on different infra
 
 ### Sidecar injector
diff --git a/docs/protocols/grpc.md b/docs/protocols/grpc.md
index f556c7b..3047ef5 100644
--- a/docs/protocols/grpc.md
+++ b/docs/protocols/grpc.md
@@ -29,3 +29,7 @@
 			return net.DialTimeout("tcp", "127.0.0.1:40101", time)
 		}))
 ```
+
+
+## example
+A gRPC example is [here](https://github.com/go-mesh/mesher-examples/tree/master/protocol/grpc-go)
diff --git a/docs/sidecar.rst b/docs/sidecar.rst
index c14df2f..7f86ad6 100644
--- a/docs/sidecar.rst
+++ b/docs/sidecar.rst
@@ -151,7 +151,7 @@
 ~~~~~~~~~~~~~~~~~~~~
 
 To use service-center following are the required annotation to be given in client and server yaml file
-sidecar.mesher.io/inject: "yes" and sidecar.mesher.io/discoveryType:"pilot"
+sidecar.mesher.io/inject: "yes" and sidecar.mesher.io/discoveryType:"sc"
 
 `Example to use sc registry <https://github.com/go-chassis/sidecar-injector/tree/master/example/WithoutServicePort/sc>`_
 
diff --git a/go.mod b/go.mod
index 92a15e2..bbadbc6 100644
--- a/go.mod
+++ b/go.mod
@@ -1,16 +1,79 @@
-module github.com/go-chassis/mesher
+module github.com/go-mesh/mesher
 
 require (
+	cloud.google.com/go v0.28.0 // indirect
+	code.cloudfoundry.org/copilot v0.0.0-20180928002835-76734bdb9045 // indirect
+	fortio.org/fortio v1.3.0 // indirect
 	github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6 // indirect
+	github.com/envoyproxy/go-control-plane v0.6.0
+
 	github.com/go-chassis/go-cc-client v0.0.0-20180831085349-c2bb6cef1640
-	github.com/go-chassis/go-chassis v0.8.2-0.20180831125844-6a2f0ab47244
+	github.com/go-chassis/go-chassis v0.8.3-0.20180914033538-0791a5cec8b4
 	github.com/go-chassis/gohessian v0.0.0-20180702061429-e5130c25af55
+	github.com/go-mesh/mesher-tools v0.0.0-20181006103649-cdc091b78a72
+	github.com/go-mesh/openlogging v0.0.0-20180831021158-f5d1c4e7e506
 	github.com/gogo/protobuf v1.1.1
+	github.com/gogo/status v1.0.3 // indirect
+	github.com/golang/groupcache v0.0.0-20180924190550-6f2cf27854a4 // indirect
+	github.com/golang/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
+	github.com/google/go-github v17.0.0+incompatible // indirect
+	github.com/google/go-querystring v1.0.0 // indirect
+	github.com/google/uuid v1.0.0 // indirect
+	github.com/gorilla/context v1.1.1 // indirect
+	github.com/gorilla/mux v1.6.2 // indirect
+	github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect
+	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
+	github.com/hashicorp/consul v1.2.3 // indirect
+	github.com/hashicorp/go-cleanhttp v0.5.0 // indirect
+	github.com/hashicorp/go-multierror v1.0.0 // indirect
+	github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90 // indirect
+	github.com/hashicorp/serf v0.8.1 // indirect
+	github.com/howeyc/fsnotify v0.9.0 // indirect
+	github.com/inconshreveable/mousetrap v1.0.0 // indirect
+	github.com/mitchellh/go-homedir v1.0.0 // indirect
+	github.com/mitchellh/mapstructure v1.0.0 // indirect
+	github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
 	github.com/patrickmn/go-cache v2.1.0+incompatible
+	github.com/pkg/errors v0.8.0 // indirect
 	github.com/prometheus/client_golang v0.8.0
 	github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910
+	github.com/prometheus/prom2json v0.0.0-20180620215746-7b8ed2aed129 // indirect
+	github.com/spf13/cobra v0.0.3 // indirect
 	github.com/stretchr/testify v1.2.2
 	github.com/urfave/cli v0.0.0-20180821064027-934abfb2f102
+	go.uber.org/atomic v1.3.2 // indirect
+	go.uber.org/multierr v1.1.0 // indirect
+	go.uber.org/zap v1.9.1 // indirect
+	golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be // indirect
+	google.golang.org/appengine v1.2.0 // indirect
 	google.golang.org/grpc v1.14.0
+	gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19 // indirect
 	gopkg.in/yaml.v2 v2.2.1
+	istio.io/api v0.0.0-20180926203357-0cf306e2fd19 // indirect
+	istio.io/fortio v1.3.0 // indirect
+	istio.io/istio v0.0.0-20180929031539-a8986e2dc2c3
+	k8s.io/apiextensions-apiserver v0.0.0-20180925155151-ce69c54e57693220512104c84941e2ef1876449a // indirect
+	k8s.io/apimachinery v0.0.0-20180823151430-fda675fbe85280c4550452dae2a5ebf74e4a59b7
+	k8s.io/client-go v8.0.0+incompatible
+	k8s.io/cluster-registry v0.0.6 // indirect
+
+	k8s.io/ingress v0.0.0-20170803151325-fe19ebb09ee2 // indirect
+	k8s.io/kube-openapi v0.0.0-20180928070517-c01ed926f124 // indirect
+)
+
+replace (
+	cloud.google.com/go v0.28.0 => github.com/GoogleCloudPlatform/google-cloud-go v0.28.0
+	github.com/envoyproxy/go-control-plane v0.6.0 => github.com/envoyproxy/go-control-plane v0.0.0-20180918192855-2137d919632883e52e7786f55f0f84e52a44fbf3
+	github.com/kubernetes/client-go => ../k8s.io/client-go
+	golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac => github.com/golang/crypto v0.0.0-20180820150726-614d502a4dac
+	golang.org/x/net v0.0.0-20180724234803-3673e40ba225 => github.com/golang/net v0.0.0-20180724234803-3673e40ba225
+	golang.org/x/net v0.0.0-20180824152047-4bcd98cce591 => github.com/golang/net v0.0.0-20180824152047-4bcd98cce591
+
+	golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be => github.com/golang/oauth2 v0.0.0-20180821212333-d2e6202438be
+	golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87 => github.com/golang/sys v0.0.0-20180824143301-4910a1d54f87
+	golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
+	golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 => github.com/golang/time v0.0.0-20180412165947-fbb02b2291d2
+	google.golang.org/appengine v1.2.0 => github.com/golang/appengine v1.2.0
+	google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 => github.com/google/go-genproto v0.0.0-20180817151627-c66870c02cf8
+	google.golang.org/grpc v1.14.0 => github.com/grpc/grpc-go v1.14.0
 )
diff --git a/go.sum b/go.sum
deleted file mode 100644
index d926a62..0000000
--- a/go.sum
+++ /dev/null
@@ -1,155 +0,0 @@
-github.com/DataDog/datadog-go v0.0.0-20180330214955-e67964b4021a/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
-github.com/Shopify/sarama v1.17.0 h1:Y2/FBwElFVwt7aLKL3fDG6hh+rrlywR6uLgTgKObwTc=
-github.com/Shopify/sarama v1.17.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
-github.com/apache/thrift v0.0.0-20180807212849-6e67faa92827 h1:47CwjpyuyVwNGpyQfraO51g8eYske6pu/mb2Q4vB3SY=
-github.com/apache/thrift v0.0.0-20180807212849-6e67faa92827/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/apache/thrift v0.0.0-20180829120307-8de3749235db h1:wK8K96PXMirNKpbyEdOuDHSGC50bDH4iOJNO5jvZeNI=
-github.com/apache/thrift v0.0.0-20180829120307-8de3749235db/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/cactus/go-statsd-client v3.1.1+incompatible/go.mod h1:cMRcwZDklk7hXp+Law83urTHUiHMzCev/r4JMYr/zU0=
-github.com/cenkalti/backoff v2.0.0+incompatible h1:5IIPUHhlnUZbcHQsQou5k1Tn58nJkeJL9U+ig5CHJbY=
-github.com/cenkalti/backoff v2.0.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/emicklei/go-restful v2.8.0+incompatible h1:wN8GCRDPGHguIynsnBartv5GUgGUg1LAU7+xnSn1j7Q=
-github.com/emicklei/go-restful v2.8.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emicklei/go-restful-swagger12 v0.0.0-20170208215640-dcef7f557305/go.mod h1:qr0VowGBT4CS4Q8vFF8BSeKz34PuqKGxs/L0IAQA9DQ=
-github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6 h1:V94anc0ZG3Pa/cAMwP2m1aQW3+/FF8Qmw/GsFyTJAp4=
-github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6/go.mod h1:qr0VowGBT4CS4Q8vFF8BSeKz34PuqKGxs/L0IAQA9DQ=
-github.com/envoyproxy/go-control-plane v0.5.0 h1:sXNEwucP7EkLn00DBvEJRXrRs5sQyZW45LzBR2AhYxs=
-github.com/envoyproxy/go-control-plane v0.5.0/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-chassis/go-archaius v0.0.0-20180801075410-885b00ca6929 h1:crQCNWCeyZTHKfHdDC7xDmXpdTAA/zXk2ou6qZXPgdI=
-github.com/go-chassis/go-archaius v0.0.0-20180801075410-885b00ca6929/go.mod h1:wahnwKS5N7/4ozbNiqPgctqjT7DxL7JH5VKd3FnSWDI=
-github.com/go-chassis/go-archaius v0.0.0-20180831094429-1e6b20d2a085 h1:iR8lcvTCIJDDyALxDLrxoLZUfiWwUJwZOaItjJXgbFY=
-github.com/go-chassis/go-archaius v0.0.0-20180831094429-1e6b20d2a085/go.mod h1:wahnwKS5N7/4ozbNiqPgctqjT7DxL7JH5VKd3FnSWDI=
-github.com/go-chassis/go-cc-client v0.0.0-20180803084655-75b751c2f183 h1:tOCz2KrXKBz1i0tE0JAkQ/fL7uXQtDcJi1CUbe0/oQo=
-github.com/go-chassis/go-cc-client v0.0.0-20180803084655-75b751c2f183/go.mod h1:6P5JmlcKZBlAVebxGgfGnKlsZ3UKLfO2VfyhJ1nO82c=
-github.com/go-chassis/go-cc-client v0.0.0-20180831085349-c2bb6cef1640 h1:o4wHmHChm8sOe++xtGXQsmeFpugdqW+yGZN2VuQaPwY=
-github.com/go-chassis/go-cc-client v0.0.0-20180831085349-c2bb6cef1640/go.mod h1:6P5JmlcKZBlAVebxGgfGnKlsZ3UKLfO2VfyhJ1nO82c=
-github.com/go-chassis/go-chassis v0.0.0-20180825083348-3f0dea26ded2 h1:EACl4+vnfD0IAqJCchdoNXP+xfmvBMZlnlARu6nRvqo=
-github.com/go-chassis/go-chassis v0.0.0-20180825083348-3f0dea26ded2/go.mod h1:yoQcnkPOT3nLE+FLITgktmqKziiXtnztO4PlVAMU/nQ=
-github.com/go-chassis/go-chassis v0.7.2-0.20180828015440-350cf4bb7119 h1:5z9ooiNcBOaLxWrL/3Rk+DQfajpT0Ipq4jRyqc4z2IM=
-github.com/go-chassis/go-chassis v0.7.2-0.20180828015440-350cf4bb7119/go.mod h1:yoQcnkPOT3nLE+FLITgktmqKziiXtnztO4PlVAMU/nQ=
-github.com/go-chassis/go-chassis v0.7.2-0.20180828032500-d9b2138fb00b h1:lYezzXzKmmPG+oYvcTAQkRZFV+1aPZPbuIpsIj1hIZY=
-github.com/go-chassis/go-chassis v0.7.2-0.20180828032500-d9b2138fb00b/go.mod h1:yoQcnkPOT3nLE+FLITgktmqKziiXtnztO4PlVAMU/nQ=
-github.com/go-chassis/go-chassis v0.8.2-0.20180831125844-6a2f0ab47244 h1:elNu5tWleXV5uZmdEpW7Y1PJD6OyhBPN+ZZSKuPWJKM=
-github.com/go-chassis/go-chassis v0.8.2-0.20180831125844-6a2f0ab47244/go.mod h1:qYnF5AEh6HjcZsDcFVwDr00K06q5BDGhdzWnmC8AtHk=
-github.com/go-chassis/go-chassis-plugins v0.0.0-20180731065901-7b05d8d2fbe6/go.mod h1:DqeW7HKONWncHIQhtEus/nNpe7N15F7c43V9p4AqaHM=
-github.com/go-chassis/go-sc-client v0.0.0-20180817094046-3be308d3a0a3 h1:gF6sWwBMfEPtEVr5aRY2yj57+CiagrcMofND1Co6CU8=
-github.com/go-chassis/go-sc-client v0.0.0-20180817094046-3be308d3a0a3/go.mod h1:evzKZXMnMFCLPc5oGHYx8MAJlQRYMptkMYdvJN8GzwI=
-github.com/go-chassis/go-sc-client v0.0.0-20180831081217-8135c6df7f96 h1:+CwasSmqeqHut6G4CxURqCqd6QcRjCl5LoUZHaL148Y=
-github.com/go-chassis/go-sc-client v0.0.0-20180831081217-8135c6df7f96/go.mod h1:IS3XXS6JdNbKP4K7duT+q2Gk8+yJq5EUh+5zTMWnCDg=
-github.com/go-chassis/gohessian v0.0.0-20180702061429-e5130c25af55 h1:7DMPFTM7YBCSWfk1G3O/EpksFz+7BcjEEGR0rUSpB2c=
-github.com/go-chassis/gohessian v0.0.0-20180702061429-e5130c25af55/go.mod h1:UkW8yQ1q1hUoiHEMadjc3psAf4nSZdDIPVP4lt4bqlE=
-github.com/go-chassis/paas-lager v0.0.0-20180727081842-50655443dc96 h1:VViSMNCEKU0iqveFWVJpmel5aGgE6UOOUr/ZHhWa8B4=
-github.com/go-chassis/paas-lager v0.0.0-20180727081842-50655443dc96/go.mod h1:tILYbn3+0jjCxhY6/ue9L8eRq+VJ60U6VYIdugqchB4=
-github.com/go-chassis/paas-lager v0.0.0-20180831030822-312e8737a225 h1:rMCN+v6YrQsliVFo/ThdZpu0XIQN6+4HHz2uPOa7/2Q=
-github.com/go-chassis/paas-lager v0.0.0-20180831030822-312e8737a225/go.mod h1:tILYbn3+0jjCxhY6/ue9L8eRq+VJ60U6VYIdugqchB4=
-github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-mesh/openlogging v0.0.0-20180831021158-f5d1c4e7e506 h1:o2Hx9jC8VVv406dDh+Dy8Hi2ZCGAGA+0WpnezaMb0DY=
-github.com/go-mesh/openlogging v0.0.0-20180831021158-f5d1c4e7e506/go.mod h1:qaKi+amO+hsGin2q1GmW+/NcbZpMPnTufwrWzDmIuuU=
-github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
-github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI=
-github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
-github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
-github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/gopherjs/gopherjs v0.0.0-20180820052304-89baedc74dd7/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/websocket v1.3.0 h1:r/LXc0VJIMd0rCMsc6DxgczaQtoCwCLatnfXmSYcXx8=
-github.com/gorilla/websocket v1.3.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8=
-github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b h1:X61dhFTE1Au92SvyF8HyAwdjWqiSdfBgFR7wTxC0+uU=
-github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/lyft/protoc-gen-validate v0.0.6 h1:4YInPV0jraTH7uUZl/xq5m9nhckBdUSAl9HlFgq1HPA=
-github.com/lyft/protoc-gen-validate v0.0.6/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU=
-github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
-github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin-contrib/zipkin-go-opentracing v0.0.0-20180726151020-b85dc675b16b h1:sM8Q+fCKUVflyDurBCk+3Cwl8KG12QAeO0eE3HzPRCg=
-github.com/openzipkin-contrib/zipkin-go-opentracing v0.0.0-20180726151020-b85dc675b16b/go.mod h1:uVHyebswE1cCXr2A73cRM2frx5ld1RJUCJkFNZ90ZiI=
-github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
-github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
-github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4=
-github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/pierrec/lz4 v2.0.3+incompatible h1:h0ipQUMRrnr+/HHhxhceftyXk4QcZsmxSNliSG75Bi0=
-github.com/pierrec/lz4 v2.0.3+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8=
-github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54=
-github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0=
-github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk=
-github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/shirou/gopsutil v0.0.0-20180801053943-8048a2e9c577/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
-github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
-github.com/smartystreets/assertions v0.0.0-20180301161246-7678a5452ebe/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v0.0.0-20170602164621-9e8dc3f972df/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
-github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
-github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
-github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/urfave/cli v0.0.0-20180821064027-934abfb2f102 h1:Er7kUEUX12vAWCp23Uv6Nrza7kEzEm/Z77amjMT7/Lo=
-github.com/urfave/cli v0.0.0-20180821064027-934abfb2f102/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277 h1:d9qaMM+ODpCq+9We41//fu/sHsTnXcrqd1en3x+GKy4=
-go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
-golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/net v0.0.0-20180824152047-4bcd98cce591 h1:4S2XUgvg3hUNTvxI307qkFPb9zKHG3Nf9TXFzX/DZZI=
-golang.org/x/net v0.0.0-20180824152047-4bcd98cce591/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87 h1:GqwDwfvIpC33dK9bA1fD+JiDUNsuAiQiEkpHqUKze4o=
-golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-k8s.io/api v0.0.0-20180824172530-dd5c735cbff9/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
-k8s.io/apimachinery v0.0.0-20180823151430-017bf4f8f588 h1:27Eed77htcD+xKyRQpbq8thV+F1tv611laPnUFMZoeg=
-k8s.io/apimachinery v0.0.0-20180823151430-017bf4f8f588/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
-k8s.io/client-go v8.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
diff --git a/integration/mesher-grafana-dashboard.json b/integration/mesher-grafana-dashboard.json
index 4baf3e0..cc5170d 100644
--- a/integration/mesher-grafana-dashboard.json
+++ b/integration/mesher-grafana-dashboard.json
@@ -203,7 +203,7 @@
           "tableColumn": "",
           "targets": [
             {
-              "expr": "count(count(requests_total{instance=~\"$node\"}) by(servicename))",
+              "expr": "count(count(requests_total{instance=~\"$node\"}) by(service_name))",
               "format": "time_series",
               "intervalFactor": 2,
               "refId": "A",
@@ -734,10 +734,10 @@
           "steppedLine": false,
           "targets": [
             {
-              "expr": "(sum(successes_total{instance=~\"$node\"}) by (servicename,appid,version))/(sum(requests_total{instance=~\"$node\"}) by  (servicename,appid,version))",
+              "expr": "(sum(successes_total{instance=~\"$node\"}) by (service_name,app,version))/(sum(requests_total{instance=~\"$node\"}) by  (service_name,app,version))",
               "format": "time_series",
               "intervalFactor": 2,
-              "legendFormat": "{{servicename}}@{{appid}}#{{version}}",
+              "legendFormat": "{{service_name}}@{{app}}#{{version}}",
               "refId": "A",
               "step": 10
             }
@@ -810,10 +810,10 @@
           "steppedLine": false,
           "targets": [
             {
-              "expr": "sum(rate(requests_total{instance=~\"$node\"} [5m])) by(servicename,appid,version)",
+              "expr": "sum(rate(requests_total{instance=~\"$node\"} [5m])) by(service_name,app,version)",
               "format": "time_series",
               "intervalFactor": 2,
-              "legendFormat": "{{servicename}}@{{appid}}#{{version}}",
+              "legendFormat": "{{service_name}}@{{app}}#{{version}}",
               "refId": "A",
               "step": 10
             }
@@ -934,7 +934,7 @@
           "tableColumn": "",
           "targets": [
             {
-              "expr": "requests_total{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"}",
+              "expr": "requests_total{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"}",
               "format": "time_series",
               "intervalFactor": 2,
               "refId": "A",
@@ -1011,7 +1011,7 @@
           "tableColumn": "",
           "targets": [
             {
-              "expr": "sum(successes_total{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"})/sum(requests_total{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"}) ",
+              "expr": "sum(successes_total{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"})/sum(requests_total{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"}) ",
               "format": "time_series",
               "intervalFactor": 2,
               "refId": "A",
@@ -1088,7 +1088,7 @@
           "tableColumn": "",
           "targets": [
             {
-              "expr": "rate(status_5xx{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"} [5m])",
+              "expr": "rate(status_5xx{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"} [5m])",
               "format": "time_series",
               "intervalFactor": 2,
               "refId": "A",
@@ -1165,7 +1165,7 @@
           "tableColumn": "",
           "targets": [
             {
-              "expr": "rate(status_4xx{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"} [5m])",
+              "expr": "rate(status_4xx{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"} [5m])",
               "format": "time_series",
               "intervalFactor": 2,
               "refId": "A",
@@ -1217,7 +1217,7 @@
           "steppedLine": false,
           "targets": [
             {
-              "expr": "sum(successes_total{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"})/sum(requests_total{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"}) ",
+              "expr": "sum(successes_total{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"})/sum(requests_total{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"}) ",
               "format": "time_series",
               "intervalFactor": 2,
               "legendFormat": "Quantile : {{quantile}}",
@@ -1293,10 +1293,10 @@
           "steppedLine": false,
           "targets": [
             {
-              "expr": "rate(requests_total{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"} [5m])",
+              "expr": "rate(requests_total{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"} [5m])",
               "format": "time_series",
               "intervalFactor": 2,
-              "legendFormat": "{{servicename}}",
+              "legendFormat": "{{service_name}}",
               "refId": "A",
               "step": 10
             }
@@ -1369,7 +1369,7 @@
           "steppedLine": false,
           "targets": [
             {
-              "expr": "request_latency_seconds{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\",version=~\"$version\"} ",
+              "expr": "request_latency_seconds{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\",version=~\"$version\"} ",
               "format": "time_series",
               "intervalFactor": 2,
               "legendFormat": "Quantile : {{quantile}}",
@@ -1945,7 +1945,7 @@
         "multi": false,
         "name": "service",
         "options": [],
-        "query": "label_values(requests_total{instance=~\"$node\"},servicename)",
+        "query": "label_values(requests_total{instance=~\"$node\"},service_name)",
         "refresh": 2,
         "regex": "",
         "sort": 1,
@@ -1967,9 +1967,9 @@
         "includeAll": false,
         "label": "",
         "multi": false,
-        "name": "appid",
+        "name": "app",
         "options": [],
-        "query": "label_values(requests_total{instance=~\"$node\",servicename=~\"$service\"},appid)",
+        "query": "label_values(requests_total{instance=~\"$node\",service_name=~\"$service\"},app)",
         "refresh": 2,
         "regex": "",
         "sort": 1,
@@ -1992,7 +1992,7 @@
         "multi": false,
         "name": "version",
         "options": [],
-        "query": "label_values(requests_total{instance=~\"$node\",servicename=~\"$service\",appid=~\"$appid\"},version)",
+        "query": "label_values(requests_total{instance=~\"$node\",service_name=~\"$service\",app=~\"$app\"},version)",
         "refresh": 2,
         "regex": "",
         "sort": 1,
diff --git a/metrics/metrics.go b/metrics/metrics.go
deleted file mode 100755
index 23b71b3..0000000
--- a/metrics/metrics.go
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-package metrics
-
-import (
-	"net/http"
-	"os"
-	"sync"
-	"time"
-
-	"github.com/go-chassis/go-chassis/core/config"
-	"github.com/go-chassis/go-chassis/core/invocation"
-	mesherconfig "github.com/go-mesh/mesher/config"
-	"github.com/prometheus/client_golang/prometheus"
-)
-
-//Constants with attributes for metrics data
-const (
-	TotalRequest          = "requests_total"
-	TotalSuccess          = "successes_total"
-	TotalFailures         = "failures_total"
-	RequestLatencySeconds = "request_latency_seconds"
-	Error4XX              = "status_4xx"
-	Error5XX              = "status_5xx"
-	ServiceName           = "servicename"
-	AppID                 = "appid"
-	Version               = "version"
-)
-
-var (
-	//LabelNames is a list with servicename, appID, version
-	LabelNames = []string{ServiceName, AppID, Version}
-	mutex      = sync.Mutex{}
-)
-
-var onceEnable sync.Once
-
-//Init function initiates all config
-func Init() {
-	mesherLabelValues := map[string]string{ServiceName: config.SelfServiceName, AppID: config.GlobalDefinition.AppID, Version: config.SelfVersion}
-	mesherStartTime := time.Now().Unix()
-	DefaultPrometheusExporter.Gauge("start_time_seconds", float64(mesherStartTime), LabelNames, mesherLabelValues)
-	mesherConfig := mesherconfig.GetConfig()
-	promConfig := getPrometheusSinker(getSystemPrometheusRegistry())
-	if mesherConfig.Admin.GoRuntimeMetrics == true {
-		onceEnable.Do(func() {
-			promConfig.PromRegistry.MustRegister(prometheus.NewProcessCollector(os.Getpid(), ""))
-			promConfig.PromRegistry.MustRegister(prometheus.NewGoCollector())
-		})
-	}
-}
-
-//RecordResponse record the response
-func RecordResponse(inv *invocation.Invocation, statusCode int) {
-	mutex.Lock()
-	defer mutex.Unlock()
-	serviceLabelValues := map[string]string{ServiceName: inv.MicroServiceName, AppID: inv.RouteTags.AppID(), Version: inv.RouteTags.Version()}
-	if statusCode >= http.StatusBadRequest && statusCode <= http.StatusUnavailableForLegalReasons {
-		DefaultPrometheusExporter.Count(Error4XX, LabelNames, serviceLabelValues)
-		DefaultPrometheusExporter.Count(TotalFailures, LabelNames, serviceLabelValues)
-	} else if statusCode >= http.StatusInternalServerError && statusCode <= http.StatusNetworkAuthenticationRequired {
-		DefaultPrometheusExporter.Count(Error5XX, LabelNames, serviceLabelValues)
-		DefaultPrometheusExporter.Count(TotalFailures, LabelNames, serviceLabelValues)
-	} else if statusCode >= http.StatusOK && statusCode <= http.StatusIMUsed {
-		DefaultPrometheusExporter.Count(TotalSuccess, LabelNames, serviceLabelValues)
-	}
-
-	DefaultPrometheusExporter.Count(TotalRequest, LabelNames, serviceLabelValues)
-}
diff --git a/pkg/infras/istio/xds.go b/pkg/infras/istio/xds.go
new file mode 100644
index 0000000..25d95a2
--- /dev/null
+++ b/pkg/infras/istio/xds.go
@@ -0,0 +1,458 @@
+package pilotv2
+
+import (
+	"context"
+	"crypto/tls"
+	"encoding/json"
+	"fmt"
+	"strings"
+
+	apiv2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
+	apiv2core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
+	apiv2endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
+	apiv2route "github.com/envoyproxy/go-control-plane/envoy/api/v2/route"
+	k8sinfra "github.com/go-mesh/mesher/pkg/infras/k8s"
+
+	"github.com/envoyproxy/go-control-plane/envoy/service/discovery/v2"
+	"github.com/go-mesh/openlogging"
+	"github.com/gogo/protobuf/proto"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
+	"k8s.io/client-go/rest"
+)
+
+//XdsClient provides the XDS API calls.
+type XdsClient struct {
+	PilotAddr   string
+	TlsConfig   *tls.Config
+	ReqCaches   map[XdsType]*XdsReqCache
+	nodeInfo    *NodeInfo
+	NodeID      string
+	NodeCluster string
+	k8sClient   *rest.RESTClient
+}
+
+//XdsType is the wrapper of string, the wrapper type should be "cds", "eds", "lds" or "rds"
+type XdsType string
+
+const (
+	TypeCds XdsType = "cds"
+	TypeEds XdsType = "eds"
+	TypeLds XdsType = "lds"
+	TypeRds XdsType = "rds"
+)
+
+//XdsReqCache stores the VersionInfo and Nonce for the XDS calls
+type XdsReqCache struct {
+	Nonce       string
+	VersionInfo string
+}
+
+//NodeInfo stores the info of the node, which will be used to make a
+//XDS call
+type NodeInfo struct {
+	PodName    string
+	Namespace  string
+	InstanceIP string
+}
+
+//XdsClusterInfo stores all the infos from a cluster name, which is in
+//the format direction|port|subset|hostName
+type XdsClusterInfo struct {
+	ClusterName  string
+	Direction    string
+	Port         string
+	Subset       string
+	HostName     string
+	ServiceName  string
+	Namespace    string
+	DomainSuffix string // DomainSuffix might not be used
+	Tags         map[string]string
+	Addrs        []string // The accessible addresses of the endpoints
+}
+
+//NewXdsClient returns the new XDS client.
+func NewXdsClient(pilotAddr string, tlsConfig *tls.Config, nodeInfo *NodeInfo, kubeconfigPath string) (*XdsClient, error) {
+	// TODO Handle the array
+	xdsClient := &XdsClient{
+		PilotAddr: pilotAddr,
+		nodeInfo:  nodeInfo,
+	}
+	xdsClient.NodeID = "sidecar~" + nodeInfo.InstanceIP + "~" + nodeInfo.PodName + "~" + nodeInfo.Namespace
+	xdsClient.NodeCluster = nodeInfo.PodName
+
+	xdsClient.ReqCaches = map[XdsType]*XdsReqCache{
+		TypeCds: {},
+		TypeEds: {},
+		TypeLds: {},
+		TypeRds: {},
+	}
+
+	if k8sClient, err := k8sinfra.CreateK8SRestClient(kubeconfigPath, "apis", "networking.istio.io", "v1alpha3"); err != nil {
+		return nil, err
+	} else {
+		xdsClient.k8sClient = k8sClient
+	}
+
+	return xdsClient, nil
+}
+
+//GetSubsetTags returns the tags of the specified subset.
+func (client *XdsClient) GetSubsetTags(namespace, hostName, subsetName string) (map[string]string, error) {
+	req := client.k8sClient.Get()
+	req.Resource("destinationrules")
+	req.Namespace(namespace)
+
+	result := req.Do()
+	rawBody, err := result.Raw()
+	if err != nil {
+		return nil, err
+	}
+
+	var drResult k8sinfra.DestinationRuleResult
+	if err := json.Unmarshal(rawBody, &drResult); err != nil {
+		return nil, err
+	}
+
+	// Find the subset
+	tags := map[string]string{}
+	for _, dr := range drResult.Items {
+		if dr.Spec.Host == hostName {
+			for _, subset := range dr.Spec.Subsets {
+				if subset.Name == subsetName {
+					for k, v := range subset.Labels {
+						tags[k] = v
+					}
+					break
+				}
+			}
+			break
+		}
+	}
+
+	return tags, nil
+}
+
+func (client *XdsClient) getGrpcConn() (*grpc.ClientConn, error) {
+	var conn *grpc.ClientConn
+	var err error
+	if client.TlsConfig != nil {
+		creds := credentials.NewTLS(client.TlsConfig)
+		conn, err = grpc.Dial(client.PilotAddr, grpc.WithTransportCredentials(creds))
+	} else {
+		conn, err = grpc.Dial(client.PilotAddr, grpc.WithInsecure())
+	}
+
+	return conn, err
+}
+
+func getAdsResClient(client *XdsClient) (v2.AggregatedDiscoveryService_StreamAggregatedResourcesClient, *grpc.ClientConn, error) {
+	conn, err := client.getGrpcConn()
+	if err != nil {
+		return nil, nil, err
+	}
+
+	adsClient := v2.NewAggregatedDiscoveryServiceClient(conn)
+	adsResClient, err := adsClient.StreamAggregatedResources(context.Background())
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return adsResClient, conn, nil
+}
+
+func (client *XdsClient) getRouterClusters(clusterName string) ([]string, error) {
+	virtualHosts, err := client.RDS(clusterName)
+	if err != nil {
+		return nil, err
+	}
+
+	routerClusters := []string{}
+	for _, h := range virtualHosts {
+		for _, r := range h.Routes {
+			routerClusters = append(routerClusters, r.GetRoute().GetCluster())
+		}
+	}
+
+	return routerClusters, nil
+}
+
+func (client *XdsClient) getVersionInfo(resType XdsType) string {
+	return client.ReqCaches[resType].VersionInfo
+}
+func (client *XdsClient) getNonce(resType XdsType) string {
+	return client.ReqCaches[resType].Nonce
+}
+
+func (client *XdsClient) setVersionInfo(resType XdsType, versionInfo string) {
+	client.ReqCaches[resType].VersionInfo = versionInfo
+}
+
+func (client *XdsClient) setNonce(resType XdsType, nonce string) {
+	client.ReqCaches[resType].Nonce = nonce
+}
+
+//CDS s the Clsuter Discovery Service API, which fetches all the clusters from istio pilot
+func (client *XdsClient) CDS() ([]apiv2.Cluster, error) {
+	adsResClient, conn, err := getAdsResClient(client)
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+
+	req := &apiv2.DiscoveryRequest{
+		TypeUrl:       "type.googleapis.com/envoy.api.v2.Cluster",
+		VersionInfo:   client.getVersionInfo(TypeCds),
+		ResponseNonce: client.getNonce(TypeCds),
+	}
+	req.Node = &apiv2core.Node{
+		// Sample taken from istio: router~172.30.77.6~istio-egressgateway-84b4d947cd-rqt45.istio-system~istio-system.svc.cluster.local-2
+		// The Node.Id should be in format {nodeType}~{ipAddr}~{serviceId~{domain}, splitted by '~'
+		// The format is required by pilot
+		Id:      client.NodeID,
+		Cluster: client.NodeCluster,
+	}
+
+	if err := adsResClient.Send(req); err != nil {
+		return nil, err
+	}
+
+	resp, err := adsResClient.Recv()
+	if err != nil {
+		return nil, err
+	}
+
+	client.setNonce(TypeCds, resp.GetNonce())
+	client.setVersionInfo(TypeCds, resp.GetVersionInfo())
+	resources := resp.GetResources()
+
+	var cluster apiv2.Cluster
+	clusters := []apiv2.Cluster{}
+	for _, res := range resources {
+		if err := proto.Unmarshal(res.GetValue(), &cluster); err != nil {
+			openlogging.GetLogger().Warnf("Failed to unmarshal cluster resource: %s", err.Error())
+		} else {
+			clusters = append(clusters, cluster)
+		}
+	}
+	return clusters, nil
+}
+
+//EDS is the Endpoint Discovery Service API, the API takes the cluster's name and return all its endpoints(which provide address and port)
+func (client *XdsClient) EDS(clusterName string) (*apiv2.ClusterLoadAssignment, error) {
+	adsResClient, conn, err := getAdsResClient(client)
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+
+	req := &apiv2.DiscoveryRequest{
+		TypeUrl:       "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment",
+		VersionInfo:   client.getVersionInfo(TypeEds),
+		ResponseNonce: client.getNonce(TypeEds),
+	}
+
+	req.Node = &apiv2core.Node{
+		Id:      client.NodeID,
+		Cluster: client.NodeCluster,
+	}
+	req.ResourceNames = []string{clusterName}
+	if err := adsResClient.Send(req); err != nil {
+		return nil, err
+	}
+
+	resp, err := adsResClient.Recv()
+	if err != nil {
+		return nil, err
+	}
+
+	resources := resp.GetResources()
+	client.setNonce(TypeEds, resp.GetNonce())
+	client.setVersionInfo(TypeEds, resp.GetVersionInfo())
+
+	var loadAssignment apiv2.ClusterLoadAssignment
+	var e error
+	// endpoints := []apiv2.ClusterLoadAssignment{}
+
+	for _, res := range resources {
+		if err := proto.Unmarshal(res.GetValue(), &loadAssignment); err != nil {
+			e = err
+		} else {
+			// The cluster's LoadAssignment will always be ONE, with Endpoints as its field
+			break
+		}
+	}
+	return &loadAssignment, e
+}
+
+//GetEndpointsByTags fetches the cluster's endpoints with tags. The tags is usually specified in a DestinationRule.
+func (client *XdsClient) GetEndpointsByTags(serviceName string, tags map[string]string) ([]apiv2endpoint.LbEndpoint, string, error) {
+	clusters, err := client.CDS()
+	if err != nil {
+		return nil, "", err
+	}
+
+	lbendpoints := []apiv2endpoint.LbEndpoint{}
+	clusterName := ""
+	for _, cluster := range clusters {
+		clusterInfo := ParseClusterName(cluster.Name)
+		if clusterInfo == nil || clusterInfo.Subset == "" || clusterInfo.ServiceName != serviceName {
+			continue
+		}
+		// So clusterInfo is not nil and subset is not empty
+		if subsetTags, err := client.GetSubsetTags(clusterInfo.Namespace, clusterInfo.ServiceName, clusterInfo.Subset); err == nil {
+			// filter with tags
+			matched := true
+			for k, v := range tags {
+				if subsetTagValue, exists := subsetTags[k]; exists == false || subsetTagValue != v {
+					matched = false
+					break
+				}
+			}
+
+			if matched { // We got the cluster!
+				clusterName = cluster.Name
+				loadAssignment, err := client.EDS(cluster.Name)
+				if err != nil {
+					return nil, clusterName, err
+				}
+
+				for _, item := range loadAssignment.Endpoints {
+					lbendpoints = append(lbendpoints, item.LbEndpoints...)
+				}
+
+				return lbendpoints, clusterName, nil
+			}
+		}
+	}
+
+	return lbendpoints, clusterName, nil
+}
+
+//RDS is the Router Discovery Service API, it returns the virtual hosts which contains Routes
+func (client *XdsClient) RDS(clusterName string) ([]apiv2route.VirtualHost, error) {
+	clusterInfo := ParseClusterName(clusterName)
+	if clusterInfo == nil {
+		return nil, fmt.Errorf("Invalid clusterName for routers: %s", clusterName)
+	}
+
+	adsResClient, conn, err := getAdsResClient(client)
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+
+	req := &apiv2.DiscoveryRequest{
+		TypeUrl:       "type.googleapis.com/envoy.api.v2.RouteConfiguration",
+		VersionInfo:   client.getVersionInfo(TypeRds),
+		ResponseNonce: client.getNonce(TypeRds),
+	}
+
+	req.Node = &apiv2core.Node{
+		Id:      client.NodeID,
+		Cluster: client.NodeCluster,
+	}
+	req.ResourceNames = []string{clusterName}
+	if err := adsResClient.Send(req); err != nil {
+		return nil, err
+	}
+
+	resp, err := adsResClient.Recv()
+	if err != nil {
+		return nil, err
+	}
+
+	resources := resp.GetResources()
+	client.setNonce(TypeRds, resp.GetNonce())
+	client.setVersionInfo(TypeRds, resp.GetVersionInfo())
+
+	var route apiv2.RouteConfiguration
+	virtualHosts := []apiv2route.VirtualHost{}
+
+	for _, res := range resources {
+		if err := proto.Unmarshal(res.GetValue(), &route); err != nil {
+			openlogging.GetLogger().Warnf("Failed to unmarshal router resource: ", err.Error())
+		} else {
+			vhosts := route.GetVirtualHosts()
+			for _, vhost := range vhosts {
+				if vhost.Name == clusterInfo.ServiceName+":"+clusterInfo.Port {
+					virtualHosts = append(virtualHosts, vhost)
+				}
+			}
+		}
+	}
+	return virtualHosts, nil
+}
+
+//LDS is the Listener Discovery Service API, which returns all the listerns
+func (client *XdsClient) LDS() ([]apiv2.Listener, error) {
+	adsResClient, conn, err := getAdsResClient(client)
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+
+	req := &apiv2.DiscoveryRequest{
+		TypeUrl:       "type.googleapis.com/envoy.api.v2.Listener",
+		VersionInfo:   client.getVersionInfo(TypeLds),
+		ResponseNonce: client.getNonce(TypeLds),
+	}
+
+	req.Node = &apiv2core.Node{
+		Id:      client.NodeID,
+		Cluster: client.NodeCluster,
+	}
+	if err := adsResClient.Send(req); err != nil {
+		return nil, err
+	}
+
+	resp, err := adsResClient.Recv()
+	if err != nil {
+		return nil, err
+	}
+
+	resources := resp.GetResources()
+	client.setNonce(TypeLds, resp.GetNonce())
+	client.setVersionInfo(TypeLds, resp.GetVersionInfo())
+
+	var listener apiv2.Listener
+	listeners := []apiv2.Listener{}
+
+	for _, res := range resources {
+		if err := proto.Unmarshal(res.GetValue(), &listener); err != nil {
+			openlogging.GetLogger().Warnf("Failed to unmarshal listener resource: ", err.Error())
+		} else {
+			listeners = append(listeners, listener)
+		}
+	}
+	return listeners, nil
+}
+
+//ParseClusterName parse the cluster's name, which is in the format direction|port|subset|hostName, the 4 items will be parsed into different fields. The hostName item will also be parsed into ServcieName, Namespace etc.
+func ParseClusterName(clusterName string) *XdsClusterInfo {
+	// clusterName format: direction|port|subset|hostName
+	// hostName format: |svc.namespace.svc.cluster.local
+
+	parts := strings.Split(clusterName, "|")
+	if len(parts) != 4 {
+		return nil
+	}
+
+	hostnameParts := strings.Split(parts[3], ".")
+	if len(hostnameParts) < 2 {
+		return nil
+	}
+
+	cluster := &XdsClusterInfo{
+		Direction:    parts[0],
+		Port:         parts[1],
+		Subset:       parts[2],
+		HostName:     parts[3],
+		ServiceName:  hostnameParts[0],
+		Namespace:    hostnameParts[1],
+		DomainSuffix: strings.Join(hostnameParts[2:], "."),
+		ClusterName:  clusterName,
+	}
+
+	return cluster
+}
diff --git a/pkg/infras/istio/xds_test.go b/pkg/infras/istio/xds_test.go
new file mode 100644
index 0000000..be3c1e1
--- /dev/null
+++ b/pkg/infras/istio/xds_test.go
@@ -0,0 +1,248 @@
+package pilotv2
+
+import (
+	"os"
+	"os/user"
+	"testing"
+	"time"
+
+	apiv2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
+	"github.com/go-chassis/go-chassis/core/lager"
+	"github.com/go-chassis/go-chassis/pkg/util/iputil"
+	testutil "github.com/go-mesh/mesher-tools/test/util"
+	"istio.io/istio/tests/util"
+)
+
+const (
+	TEST_POD_NAME     = "testpod"
+	NAMESPACE_DEFAULT = "default"
+)
+
+var (
+	ValidXdsClient *XdsClient
+	TestClusters   []apiv2.Cluster
+)
+var (
+	KubeConfig     string
+	ValidPilotAddr string
+	LocalIPAddress string
+	nodeInfo       *NodeInfo
+
+	err error
+)
+
+func TestMain(t *testing.T) {
+	lager.Initialize("", "DEBUG", "", "size", true, 1, 10, 7)
+	// Get kube config path and local ip
+	if KUBE_CONFIG := os.Getenv("KUBE_CONFIG"); KUBE_CONFIG != "" {
+		KubeConfig = KUBE_CONFIG
+	} else {
+		usr, err := user.Current()
+		if err != nil {
+			panic("Failed to get current user info: " + err.Error())
+		} else {
+			KubeConfig = usr.HomeDir + "/" + ".kube/config"
+		}
+	}
+
+	if PILOT_ADDR := os.Getenv("PILOT_ADDR"); PILOT_ADDR != "" {
+		ValidPilotAddr = PILOT_ADDR
+	} else {
+		// panic("PILOT_ADDR should be specified to pass the pilot address")
+		testutil.InitLocalPilotTestEnv(t)
+		ValidPilotAddr = util.MockPilotGrpcAddr
+	}
+
+	if INSTANCE_IP := os.Getenv("INSTANCE_IP"); INSTANCE_IP != "" {
+		LocalIPAddress = INSTANCE_IP
+	} else if LocalIPAddress = iputil.GetLocalIP(); LocalIPAddress == "" {
+		panic("Failed to get the local ip address, please check the network environment")
+	}
+
+	nodeInfo = &NodeInfo{
+		PodName:    TEST_POD_NAME,
+		Namespace:  NAMESPACE_DEFAULT,
+		InstanceIP: LocalIPAddress,
+	}
+}
+
+func TestNewXdsClient(t *testing.T) {
+	client, err := NewXdsClient(ValidPilotAddr, nil, nodeInfo, KubeConfig)
+
+	if err != nil {
+		t.Errorf("Failed to create xds client: %s", err.Error())
+	}
+
+	ValidXdsClient = client
+}
+
+func TestCDS(t *testing.T) {
+	clusters, err := ValidXdsClient.CDS()
+	if err != nil {
+		t.Errorf("Failed to get clusters by CDS: %s", err.Error())
+	}
+
+	t.Logf("Got %d clusters\n", len(clusters))
+	TestClusters = clusters
+}
+
+func TestEDS(t *testing.T) {
+	if len(TestClusters) == 0 { // With istio, there should always be clusters
+		t.Errorf("No clusters found")
+	}
+
+	loadAssignment, err := ValidXdsClient.EDS(TestClusters[0].Name)
+	if err != nil {
+		t.Errorf("Failed to get endpoints by EDS: %s", err.Error())
+	}
+
+	if loadAssignment == nil {
+		t.Errorf("Failed to get load assginment with EDS: %s", err.Error())
+	}
+}
+
+func TestRDS(t *testing.T) {
+	targetClusterName := ""
+	for _, c := range TestClusters {
+		info := ParseClusterName(c.Name)
+		if info != nil {
+			targetClusterName = c.Name
+			break
+		}
+	}
+
+	if targetClusterName == "" {
+		t.Log("We don't find a valid cluster")
+	}
+
+	_, err := ValidXdsClient.RDS(targetClusterName)
+	if err != nil {
+		t.Errorf("Failed to get routers: %s", err.Error())
+	}
+}
+
+func TestLDS(t *testing.T) {
+	listeners, err := ValidXdsClient.LDS()
+	if err != nil {
+		t.Errorf("Failed to get listeners with LDS: %s", err.Error())
+	}
+
+	t.Logf("%d listeners found\n", len(listeners))
+}
+
+func TestNonce(t *testing.T) {
+	nowStr := time.Now().String()
+	ValidXdsClient.setNonce(TypeCds, nowStr)
+	ValidXdsClient.setNonce(TypeEds, nowStr)
+	ValidXdsClient.setNonce(TypeRds, nowStr)
+	ValidXdsClient.setNonce(TypeLds, nowStr)
+
+	cdsNonce := ValidXdsClient.getNonce(TypeCds)
+	if cdsNonce != nowStr {
+		t.Errorf("Failed to test nonce: %s should be equal to %s", cdsNonce, nowStr)
+	}
+
+	edsNonce := ValidXdsClient.getNonce(TypeEds)
+	if edsNonce != nowStr {
+		t.Errorf("Failed to test nonce: %s should be equal to %s", edsNonce, nowStr)
+	}
+
+	ldsNonce := ValidXdsClient.getNonce(TypeLds)
+	if ldsNonce != nowStr {
+		t.Errorf("Failed to test nonce: %s should be equal to %s", ldsNonce, nowStr)
+	}
+
+	rdsNonce := ValidXdsClient.getNonce(TypeRds)
+	if rdsNonce != nowStr {
+		t.Errorf("Failed to test nonce: %s should be equal to %s", rdsNonce, nowStr)
+	}
+}
+
+func TestVersionInfo(t *testing.T) {
+	nowStr := time.Now().String()
+	ValidXdsClient.setVersionInfo(TypeCds, nowStr)
+	ValidXdsClient.setVersionInfo(TypeEds, nowStr)
+	ValidXdsClient.setVersionInfo(TypeRds, nowStr)
+	ValidXdsClient.setVersionInfo(TypeLds, nowStr)
+
+	cdsVersionInfo := ValidXdsClient.getVersionInfo(TypeCds)
+	if cdsVersionInfo != nowStr {
+		t.Errorf("Failed to test VersionInfo: %s should be equal to %s", cdsVersionInfo, nowStr)
+	}
+
+	edsVersionInfo := ValidXdsClient.getVersionInfo(TypeEds)
+	if edsVersionInfo != nowStr {
+		t.Errorf("Failed to test VersionInfo: %s should be equal to %s", edsVersionInfo, nowStr)
+	}
+
+	ldsVersionInfo := ValidXdsClient.getVersionInfo(TypeLds)
+	if ldsVersionInfo != nowStr {
+		t.Errorf("Failed to test VersionInfo: %s should be equal to %s", ldsVersionInfo, nowStr)
+	}
+
+	rdsVersionInfo := ValidXdsClient.getVersionInfo(TypeRds)
+	if rdsVersionInfo != nowStr {
+		t.Errorf("Failed to test VersionInfo: %s should be equal to %s", rdsVersionInfo, nowStr)
+	}
+}
+
+func TestGetSubsetTags(t *testing.T) {
+	var targetClusterInfo *XdsClusterInfo = nil
+	for _, c := range TestClusters {
+		if info := ParseClusterName(c.Name); info != nil && info.Subset != "" {
+			targetClusterInfo = info
+			break
+		}
+	}
+
+	if targetClusterInfo == nil {
+		t.Log("No tagged services in test environment, skip")
+	} else {
+		tags, err := ValidXdsClient.GetSubsetTags(targetClusterInfo.Namespace, targetClusterInfo.ServiceName, targetClusterInfo.Subset)
+		if err != nil {
+			t.Errorf("Failed to get subset tags: %s", err.Error())
+		} else if len(tags) == 0 {
+			t.Logf("Should not return empty tags %s", targetClusterInfo.ClusterName)
+		}
+	}
+}
+
+func TestGetAdsResClient(t *testing.T) {
+	_, conn, err := getAdsResClient(ValidXdsClient)
+
+	if err != nil {
+		t.Errorf("Failed to get ads resource client: %s", err.Error())
+	}
+	conn.Close()
+}
+
+func TestParseClusterName(t *testing.T) {
+	validClusterName := "inbound|3030||client.default.svc.cluster.local"
+
+	clusterInfo := ParseClusterName(validClusterName)
+
+	if clusterInfo == nil {
+		t.Errorf("Failed to parse cluster name: %s, should return cluster info", validClusterName)
+	}
+	if clusterInfo.Direction != "inbound" {
+		t.Errorf("Failed to parse cluster name: %s, direction should be inbound", validClusterName)
+	}
+	if clusterInfo.Port != "3030" {
+		t.Errorf("Failed to parse cluster name: %s, port should be 3030", validClusterName)
+	}
+	if clusterInfo.ServiceName != "client" {
+		t.Errorf("Failed to parse cluster name: %s, servicename should be client", validClusterName)
+	}
+
+	invalidClusterName := "BlackHoleCluster"
+	clusterInfo = ParseClusterName(invalidClusterName)
+	if clusterInfo != nil {
+		t.Errorf("Failed to parse cluster name: %s, should return nil", validClusterName)
+	}
+
+	invalidClusterName = "outbound|9080|v2|black"
+	clusterInfo = ParseClusterName(invalidClusterName)
+	if clusterInfo != nil {
+		t.Errorf("Failed to parse cluster name: %s, should return nil", validClusterName)
+	}
+}
diff --git a/pkg/infras/k8s/k8s.go b/pkg/infras/k8s/k8s.go
new file mode 100644
index 0000000..998d652
--- /dev/null
+++ b/pkg/infras/k8s/k8s.go
@@ -0,0 +1,60 @@
+package pilotv2
+
+import (
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/runtime/serializer"
+	"k8s.io/client-go/rest"
+	"k8s.io/client-go/tools/clientcmd"
+)
+
+//DestinationRuleResult is the list of MinDestinationRules
+type DestinationRuleResult struct {
+	Items []MinDestinationRule
+}
+
+// MinDestinationRule is the minimum structure we need to get subsets
+type MinDestinationRule struct {
+	Metadata struct {
+		Name      string `json:"name"`
+		Namespace string `json:"namespace"`
+	} `json:"metadata"`
+	Spec struct {
+		Host    string `json:"host"`
+		Subsets []struct {
+			Labels map[string]string `json:"labels"`
+			Name   string            `json:"name"`
+		} `json:"subsets"`
+	} `json:"spec"`
+}
+
+//CreateK8SRestClient returns the kubernetes client for RESTful API calls
+func CreateK8SRestClient(kubeconfig, apiPath, group, version string) (*rest.RESTClient, error) {
+	var config *rest.Config
+	var err error
+	if kubeconfig != "" {
+		config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
+		if err != nil {
+			config, err = rest.InClusterConfig()
+		}
+	} else {
+		config, err = rest.InClusterConfig()
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	config.APIPath = apiPath
+	config.GroupVersion = &schema.GroupVersion{
+		Group:   group,
+		Version: version,
+	}
+	config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(runtime.NewScheme())}
+
+	k8sRestClient, err := rest.RESTClientFor(config)
+	if err != nil {
+		return nil, err
+	}
+	return k8sRestClient, nil
+}
diff --git a/pkg/infras/k8s/k8s_test.go b/pkg/infras/k8s/k8s_test.go
new file mode 100644
index 0000000..3a6992c
--- /dev/null
+++ b/pkg/infras/k8s/k8s_test.go
@@ -0,0 +1,42 @@
+package pilotv2
+
+import (
+	"os"
+	"os/user"
+	"testing"
+)
+
+var KubeConfig string
+
+func init() {
+	if KUBE_CONFIG := os.Getenv("KUBE_CONFIG"); KUBE_CONFIG != "" {
+		KubeConfig = KUBE_CONFIG
+	} else {
+		usr, err := user.Current()
+		if err != nil {
+			panic("Failed to get current user info: " + err.Error())
+		} else {
+			KubeConfig = usr.HomeDir + "/" + ".kube/config"
+		}
+	}
+
+}
+
+func TestCreateK8sClient(t *testing.T) {
+	_, err := CreateK8SRestClient(KubeConfig, "apis", "networking.istio.io", "v1alpha3")
+	if err != nil {
+		t.Errorf("Failed to create k8s rest client: %s", err.Error())
+	}
+
+	_, err = CreateK8SRestClient("*nonfile", "apis", "networking.istio.io", "v1alpha3")
+	if err == nil {
+		t.Errorf("Test failed, should return error with invalid kube config path")
+	}
+}
+
+func TestCreateInvalidK8sClient(t *testing.T) {
+	_, err := CreateK8SRestClient("", "apis", "networking.istio.io", "v1alpha3")
+	if err == nil {
+		t.Errorf("Passing a nil config for k8s client should return error")
+	}
+}
diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go
new file mode 100644
index 0000000..6cc85b4
--- /dev/null
+++ b/pkg/metrics/metrics.go
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+//Package metrics is a system-independent module
+//it consider metrics key as first-class citizen
+//each function is for recording one kind of metrics key and value
+//it expose standard API to record runtime metrics for a service
+//use prom as default metrics system
+package metrics
+
+import (
+	"github.com/go-chassis/go-chassis/pkg/runtime"
+	mesherConf "github.com/go-mesh/mesher/config"
+	"sync"
+	"time"
+)
+
+//Constants with attributes for metrics data
+//Label start with word "L"
+const (
+	LTotalRequest          = "requests_total"
+	LTotalSuccess          = "successes_total"
+	LTotalFailures         = "failures_total"
+	LRequestLatencySeconds = "request_latency_seconds"
+	LError4XX              = "status_4xx"
+	LError5XX              = "status_5xx"
+	LServiceName           = "service_name"
+	LApp                   = "app"
+	LVersion               = "version"
+	LStartTime             = "start_time_seconds"
+)
+
+var (
+	//LabelNames is a fixed list with service name, appID, version
+	LabelNames = []string{LServiceName, LApp, LVersion}
+	mutex      = sync.Mutex{}
+)
+
+//Recorder export the metrics into various of system
+type Recorder interface {
+	RecordStatus(labelValues map[string]string, status int, opts *RecordOptions)
+	RecordLatency(labelValues map[string]string, latency float64, opts *RecordOptions)
+	RecordStartTime(labelValues map[string]string, start time.Time, opts *RecordOptions)
+}
+
+//Options define recorder options
+type Options struct {
+	LabelNames             []string //default label names, if RecordOptions LabelNames is nil
+	EnableGoRuntimeMetrics bool
+}
+
+//RecordOptions is options for record method
+type RecordOptions struct {
+	LabelNames []string // able top custom label names
+}
+
+var defaultRecorder Recorder = &promRecorder{}
+
+//RecordStatus record an operation status
+func RecordStatus(labelValues map[string]string, statusCode int, opts *RecordOptions) {
+	defaultRecorder.RecordStatus(labelValues, statusCode, opts)
+}
+
+//RecordLatency record an operation latency
+func RecordLatency(labelValues map[string]string, latency float64, opts *RecordOptions) {
+	defaultRecorder.RecordLatency(labelValues, latency, opts)
+}
+
+//RecordStartTime record app start time
+func RecordStartTime(labelValues map[string]string, start time.Time, opts *RecordOptions) {
+	defaultRecorder.RecordStartTime(labelValues, start, opts)
+}
+
+//Init initiate the recorder
+func Init() error {
+	var err error
+	LabelValues := map[string]string{LServiceName: runtime.ServiceName, LApp: runtime.App, LVersion: runtime.Version}
+	defaultRecorder, err = NewPromRecorder(&Options{
+		LabelNames:             LabelNames,
+		EnableGoRuntimeMetrics: mesherConf.GetConfig().Admin.GoRuntimeMetrics,
+	})
+	if err != nil {
+		return err
+	}
+	RecordStartTime(LabelValues, time.Now(), nil)
+	return nil
+}
diff --git a/pkg/metrics/metrics_test.go b/pkg/metrics/metrics_test.go
new file mode 100644
index 0000000..ed1bbd1
--- /dev/null
+++ b/pkg/metrics/metrics_test.go
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package metrics_test
+
+import (
+	"net/http"
+	"strings"
+	"testing"
+
+	"github.com/prometheus/client_golang/prometheus"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/go-chassis/go-chassis/pkg/runtime"
+	mc "github.com/go-mesh/mesher/config"
+	"github.com/go-mesh/mesher/pkg/metrics"
+)
+
+func TestInit(t *testing.T) {
+	mc.SetConfig(&mc.MesherConfig{
+		Admin: mc.Admin{
+			GoRuntimeMetrics: false,
+		},
+	})
+	err := metrics.Init()
+	runtime.ServiceName = "A"
+	runtime.Version = "v1.1"
+	runtime.App = "app"
+	assert.NoError(t, err)
+}
+func TestRecordStatus(t *testing.T) {
+	assert := assert.New(t)
+	var errorcount4xx float64
+	var errorcount5xx float64
+	lvs := map[string]string{
+		metrics.LServiceName: "service",
+		metrics.LVersion:     "",
+		metrics.LApp:         "",
+	}
+	metrics.RecordStatus(lvs, http.StatusOK, nil)
+	metrics.RecordStatus(lvs, http.StatusNotFound, nil)
+	metrics.RecordStatus(lvs, http.StatusInternalServerError, nil)
+	metricFamilies, err := prometheus.DefaultGatherer.Gather()
+	assert.Nil(err, "error should be nil while collecting metrics from prometheus")
+	for _, metricFamily := range metricFamilies {
+		if name := metricFamily.GetName(); strings.Contains(name, metrics.LError5XX) {
+			errorcount4xx += *metricFamily.Metric[0].Counter.Value
+		}
+	}
+	for _, metricFamily := range metricFamilies {
+		if name := metricFamily.GetName(); strings.Contains(name, metrics.LError5XX) {
+			errorcount5xx += *metricFamily.Metric[0].Counter.Value
+		}
+	}
+	assert.Equal(errorcount4xx, float64(1))
+	assert.Equal(errorcount5xx, float64(1))
+
+}
diff --git a/pkg/metrics/prom_recorder.go b/pkg/metrics/prom_recorder.go
new file mode 100644
index 0000000..a1bc62d
--- /dev/null
+++ b/pkg/metrics/prom_recorder.go
@@ -0,0 +1,69 @@
+package metrics
+
+import (
+	"errors"
+	"github.com/prometheus/client_golang/prometheus"
+	"net/http"
+	"os"
+	"sync"
+	"time"
+)
+
+var onceEnable sync.Once
+
+type promRecorder struct {
+	LabelNames []string
+}
+
+//NewPromRecorder return a prom recorder
+func NewPromRecorder(opts *Options) (Recorder, error) {
+	promConfig := getPrometheusSinker(getSystemPrometheusRegistry())
+	if opts != nil {
+		if opts.EnableGoRuntimeMetrics {
+			onceEnable.Do(func() {
+				promConfig.PromRegistry.MustRegister(prometheus.NewProcessCollector(os.Getpid(), ""))
+				promConfig.PromRegistry.MustRegister(prometheus.NewGoCollector())
+			})
+		}
+		return &promRecorder{LabelNames: opts.LabelNames}, nil
+	}
+	return nil, errors.New("options can not be nil")
+}
+
+//GetLN return label names based on options
+func (e *promRecorder) GetLN(opts *RecordOptions) (ln []string) {
+	ln = e.LabelNames
+	if opts != nil && len(opts.LabelNames) != 0 {
+		ln = opts.LabelNames
+	}
+	return
+}
+
+//RecordStatus record different metrics based on status
+func (e *promRecorder) RecordStatus(LabelValues map[string]string, statusCode int, opts *RecordOptions) {
+	ln := e.GetLN(opts)
+	if statusCode >= http.StatusBadRequest && statusCode <= http.StatusUnavailableForLegalReasons {
+		DefaultPrometheusExporter.Count(LError4XX, ln, LabelValues)
+		DefaultPrometheusExporter.Count(LTotalFailures, ln, LabelValues)
+	} else if statusCode >= http.StatusInternalServerError && statusCode <= http.StatusNetworkAuthenticationRequired {
+		DefaultPrometheusExporter.Count(LError5XX, ln, LabelValues)
+		DefaultPrometheusExporter.Count(LTotalFailures, ln, LabelValues)
+	} else if statusCode >= http.StatusOK && statusCode <= http.StatusIMUsed {
+		DefaultPrometheusExporter.Count(LTotalSuccess, ln, LabelValues)
+	}
+	DefaultPrometheusExporter.Count(LTotalRequest, ln, LabelValues)
+}
+
+//RecordLatency record operation latency
+func (e *promRecorder) RecordLatency(LabelValues map[string]string, latency float64, opts *RecordOptions) {
+	ln := e.GetLN(opts)
+	DefaultPrometheusExporter.Summary(LRequestLatencySeconds, latency, ln, LabelValues)
+
+}
+
+//RecordStartTime save start time
+func (e *promRecorder) RecordStartTime(LabelValues map[string]string, start time.Time, opts *RecordOptions) {
+	ln := e.GetLN(opts)
+	DefaultPrometheusExporter.Gauge(LStartTime, float64(start.Unix()), ln, LabelValues)
+
+}
diff --git a/pkg/metrics/prom_recorder_test.go b/pkg/metrics/prom_recorder_test.go
new file mode 100644
index 0000000..065c342
--- /dev/null
+++ b/pkg/metrics/prom_recorder_test.go
@@ -0,0 +1,12 @@
+package metrics
+
+import (
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestNewPromRecorder(t *testing.T) {
+	_,err := NewPromRecorder(nil)
+	assert.Error(t, err)
+
+}
diff --git a/metrics/prometheus.go b/pkg/metrics/prometheus_exporter.go
similarity index 100%
rename from metrics/prometheus.go
rename to pkg/metrics/prometheus_exporter.go
diff --git a/metrics/metrics_test.go b/pkg/metrics/prometheusexporter_test.go
similarity index 72%
rename from metrics/metrics_test.go
rename to pkg/metrics/prometheusexporter_test.go
index 526586b..fa8215e 100644
--- a/metrics/metrics_test.go
+++ b/pkg/metrics/prometheusexporter_test.go
@@ -18,17 +18,12 @@
 package metrics
 
 import (
-	"net/http"
 	"strings"
 	"testing"
 
-	"github.com/go-chassis/go-chassis/core/config"
-	"github.com/go-chassis/go-chassis/core/invocation"
 	"github.com/prometheus/client_golang/prometheus"
 	dto "github.com/prometheus/client_model/go"
 	"github.com/stretchr/testify/assert"
-
-	"github.com/go-chassis/go-chassis/core/config/model"
 )
 
 var (
@@ -86,33 +81,3 @@
 	assert.Equal(totalMetricCreated, 1)
 	assert.Equal(*sampleCount, uint64(1))
 }
-
-func TestPrepare(t *testing.T) {
-	assert := assert.New(t)
-	config.GlobalDefinition = new(model.GlobalCfg)
-	config.GlobalDefinition.AppID = "sockshop"
-	config.SelfVersion = "0.1"
-	var inv = &invocation.Invocation{
-		MicroServiceName: "service",
-	}
-	var errorcount4xx float64
-	var errorcount5xx float64
-	RecordResponse(inv, http.StatusOK)
-	RecordResponse(inv, http.StatusNotFound)
-	RecordResponse(inv, http.StatusInternalServerError)
-	metricFamilies, err := prometheus.DefaultGatherer.Gather()
-	assert.Nil(err, "error should be nil while collecting metrics from prometheus")
-	for _, metricFamily := range metricFamilies {
-		if name := metricFamily.GetName(); strings.Contains(name, Error5XX) {
-			errorcount4xx += *metricFamily.Metric[0].Counter.Value
-		}
-	}
-	for _, metricFamily := range metricFamilies {
-		if name := metricFamily.GetName(); strings.Contains(name, Error5XX) {
-			errorcount5xx += *metricFamily.Metric[0].Counter.Value
-		}
-	}
-	assert.Equal(errorcount4xx, float64(1))
-	assert.Equal(errorcount5xx, float64(1))
-
-}
diff --git a/pkg/runtime/runtime.go b/pkg/runtime/runtime.go
new file mode 100644
index 0000000..bf2603c
--- /dev/null
+++ b/pkg/runtime/runtime.go
@@ -0,0 +1,6 @@
+package runtime
+
+var (
+	//Mode is of type string which gives mode of mesher deployment
+	Mode string
+)
diff --git a/plugins/registry/istiov2/cache.go b/plugins/registry/istiov2/cache.go
new file mode 100644
index 0000000..ec05328
--- /dev/null
+++ b/plugins/registry/istiov2/cache.go
@@ -0,0 +1,286 @@
+package istiov2
+
+import (
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	apiv2endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
+	istioinfra "github.com/go-mesh/mesher/pkg/infras/istio"
+
+	"github.com/go-chassis/go-chassis/core/archaius"
+	"github.com/go-chassis/go-chassis/core/common"
+	"github.com/go-chassis/go-chassis/core/config"
+	"github.com/go-chassis/go-chassis/core/lager"
+	"github.com/go-chassis/go-chassis/core/registry"
+)
+
+const (
+	DefaultRefreshInterval = time.Second * 30
+)
+
+var simpleCache *EndpointCache
+
+func init() {
+	simpleCache = &EndpointCache{
+		cache: map[string]EndpointSubset{},
+	}
+}
+
+//CacheManager manages the caches for istio pilot results.
+type CacheManager struct {
+	xdsClient *istioinfra.XdsClient
+}
+
+//AutoSync fetches and updates the cluster and endpoint info periodically
+func (cm *CacheManager) AutoSync() {
+	cm.refreshCache()
+
+	var ticker *time.Ticker
+	refreshInterval := config.GetServiceDiscoveryRefreshInterval()
+	if refreshInterval == "" {
+		ticker = time.NewTicker(DefaultRefreshInterval)
+	} else {
+		timeValue, err := time.ParseDuration(refreshInterval)
+		if err != nil {
+			lager.Logger.Errorf("refeshInterval is invalid. So use Default value: %s", err.Error())
+			timeValue = DefaultRefreshInterval
+		}
+
+		ticker = time.NewTicker(timeValue)
+	}
+	go func() {
+		for range ticker.C {
+			cm.refreshCache()
+		}
+	}()
+}
+
+func (cm *CacheManager) refreshCache() {
+	// TODO What is the design of autodiscovery
+	if archaius.GetBool("cse.service.registry.autodiscovery", false) {
+		lager.Logger.Errorf("SyncPilotEndpoints failed: not supported")
+	}
+
+	err := cm.pullMicroserviceInstance()
+	if err != nil {
+		lager.Logger.Errorf("AutoUpdateMicroserviceInstance failed: %s", err.Error())
+	}
+
+	if archaius.GetBool("cse.service.registry.autoSchemaIndex", false) {
+		lager.Logger.Errorf("MakeSchemaIndex failed: Not support operation")
+	}
+
+	if archaius.GetBool("cse.service.registry.autoIPIndex", false) {
+		err = cm.MakeIPIndex()
+		if err != nil {
+			lager.Logger.Errorf("Auto Update IP index failed: %s", err.Error())
+		}
+	}
+}
+
+func (cm *CacheManager) pullMicroserviceInstance() error {
+	clusterInfos, err := cm.getClusterInfos()
+	if err != nil {
+		return err
+	}
+
+	for _, clusterInfo := range clusterInfos {
+		if clusterInfo.Subset != "" {
+			// Update the cache
+			instances := []*registry.MicroServiceInstance{}
+			for _, addr := range clusterInfo.Addrs {
+				msi := &registry.MicroServiceInstance{}
+				msi.InstanceID = strings.Replace(addr, ":", "_", 0)
+				msi.HostName = clusterInfo.ClusterName
+				msi.EndpointsMap = map[string]string{
+					common.ProtocolRest: addr,
+				}
+				msi.DefaultEndpoint = addr
+				msi.DefaultProtocol = common.ProtocolRest
+				msi.Metadata = clusterInfo.Tags
+
+				instances = append(instances, msi)
+			}
+
+			endpointSubset := EndpointSubset{
+				tags:       clusterInfo.Tags,
+				instances:  instances,
+				subsetName: clusterInfo.Subset,
+			}
+			simpleCache.Set(clusterInfo.ClusterName, endpointSubset)
+		}
+	}
+
+	return nil
+}
+
+//MakeIPIndex caches the cluster info with address as the key
+func (cm *CacheManager) MakeIPIndex() error {
+	// TODO Use getClusterInfo to replace the logic
+	clusterInfos, err := cm.getClusterInfos()
+	if err != nil {
+		return err
+	}
+
+	for _, clusterInfo := range clusterInfos {
+		for _, addr := range clusterInfo.Addrs {
+			si := &registry.SourceInfo{}
+			// TODO Get tags by subset and put them into si.Tags
+			si.Name = clusterInfo.ClusterName
+			si.Tags = clusterInfo.Tags
+			registry.SetIPIndex(addr, si)
+			// TODO Why don't we have to index every endpoint?
+			// break
+		}
+	}
+
+	return nil
+}
+
+//NewCacheManager creates the CacheManager instance.
+func NewCacheManager(xdsClient *istioinfra.XdsClient) (*CacheManager, error) {
+	cacheManager := &CacheManager{
+		xdsClient: xdsClient,
+	}
+
+	return cacheManager, nil
+}
+
+func (cm *CacheManager) getClusterInfos() ([]istioinfra.XdsClusterInfo, error) {
+	clusterInfos := []istioinfra.XdsClusterInfo{}
+
+	clusters, err := cm.xdsClient.CDS()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, cluster := range clusters {
+		// xDS v2 API: CDS won't obtain the cluster's endpoints, call EDS to get the endpoints
+
+		clusterInfo := istioinfra.ParseClusterName(cluster.Name)
+		if clusterInfo == nil {
+			continue
+		}
+
+		// Get Tags
+		if clusterInfo.Subset != "" { // Only clusters with subset contain labels
+			if tags, err := cm.xdsClient.GetSubsetTags(clusterInfo.Namespace, clusterInfo.ServiceName, clusterInfo.Subset); err == nil {
+				clusterInfo.Tags = tags
+			}
+		}
+
+		// Get cluster instances' addresses
+		loadAssignment, err := cm.xdsClient.EDS(cluster.Name)
+		if err != nil {
+			return nil, err
+		}
+		endpoints := loadAssignment.Endpoints
+		for _, endpoint := range endpoints {
+			for _, lbendpoint := range endpoint.LbEndpoints {
+				socketAddress := lbendpoint.Endpoint.Address.GetSocketAddress()
+				addr := socketAddress.GetAddress()
+				port := socketAddress.GetPortValue()
+				ipAddr := addr + ":" + strconv.FormatUint(uint64(port), 10)
+				clusterInfo.Addrs = append(clusterInfo.Addrs, ipAddr)
+			}
+		}
+
+		clusterInfos = append(clusterInfos, *clusterInfo)
+	}
+	return clusterInfos, nil
+}
+
+// TODO Cache with registry index cache
+func updateInstanceIndexCache(lbendpoints []apiv2endpoint.LbEndpoint, clusterName string, tags map[string]string) {
+	if len(lbendpoints) == 0 {
+		simpleCache.Delete(clusterName)
+		return
+	}
+
+	instances := make([]*registry.MicroServiceInstance, 0, len(lbendpoints))
+	for _, lbendpoint := range lbendpoints {
+		msi := toMicroServiceInstance(clusterName, &lbendpoint, tags)
+		instances = append(instances, msi)
+	}
+	subset := EndpointSubset{
+		tags:      tags,
+		instances: instances,
+	}
+
+	info := istioinfra.ParseClusterName(clusterName)
+	if info != nil {
+		subset.subsetName = info.Subset
+	}
+
+	simpleCache.Set(clusterName, subset)
+}
+
+//EndpointCache caches the clusters' endpoint and tags
+type EndpointCache struct {
+	mux   sync.Mutex
+	cache map[string]EndpointSubset
+}
+
+//EndpointSubset stores the tags and instances of a service
+type EndpointSubset struct {
+	subsetName string
+	tags       map[string]string
+	instances  []*registry.MicroServiceInstance
+}
+
+//Delete removes the cached instances of the specified cluster
+func (c *EndpointCache) Delete(clusterName string) {
+	c.mux.Lock()
+	delete(c.cache, clusterName)
+	c.mux.Unlock()
+}
+
+//Set updates the cluster's instance info
+func (c *EndpointCache) Set(clusterName string, subset EndpointSubset) {
+	c.mux.Lock()
+	c.cache[clusterName] = subset
+	c.mux.Unlock()
+}
+
+//GetWithTags returns the instances of the service, filtered with tags
+func (c *EndpointCache) GetWithTags(serviceName string, tags map[string]string) []*registry.MicroServiceInstance {
+	// Get subsets whose clusterName matches the service name
+	matchedSubsets := []EndpointSubset{}
+	c.mux.Lock()
+	for clusterName, subset := range c.cache {
+		info := istioinfra.ParseClusterName(clusterName)
+		if info != nil && info.ServiceName == serviceName {
+			matchedSubsets = append(matchedSubsets, subset)
+		}
+	}
+	c.mux.Unlock()
+
+	if len(matchedSubsets) == 0 {
+		return nil
+	}
+
+	var instances []*registry.MicroServiceInstance
+
+	for _, subset := range matchedSubsets {
+		if tagsMatch(subset.tags, tags) {
+			instances = subset.instances
+			break
+		}
+
+	}
+	return instances
+}
+
+// TODO There might be some utils in go-chassis doing the same thing
+func tagsMatch(tags, targetTags map[string]string) bool {
+	matched := true
+	for k, v := range targetTags {
+		if val, exists := tags[k]; !exists || val != v {
+			matched = false
+			break
+		}
+	}
+	return matched
+}
diff --git a/plugins/registry/istiov2/cache_test.go b/plugins/registry/istiov2/cache_test.go
new file mode 100644
index 0000000..6eedd34
--- /dev/null
+++ b/plugins/registry/istiov2/cache_test.go
@@ -0,0 +1,126 @@
+package istiov2
+
+import (
+	"os"
+	"os/user"
+	"testing"
+
+	"github.com/go-chassis/go-chassis/core/lager"
+	"github.com/go-chassis/go-chassis/core/registry"
+	"github.com/go-chassis/go-chassis/pkg/util/iputil"
+	testutil "github.com/go-mesh/mesher-tools/test/util"
+	istioinfra "github.com/go-mesh/mesher/pkg/infras/istio"
+	"istio.io/istio/tests/util"
+)
+
+const (
+	TEST_POD_NAME     = "testpod"
+	NAMESPACE_DEFAULT = "default"
+)
+
+var (
+	KubeConfig     string
+	ValidPilotAddr string
+	LocalIPAddress string
+	nodeInfo       *istioinfra.NodeInfo
+
+	testXdsClient    *istioinfra.XdsClient
+	testCacheManager *CacheManager
+	err              error
+)
+
+func TestMain(t *testing.T) {
+	lager.Initialize("", "DEBUG", "", "size", true, 1, 10, 7)
+	// Get kube config path and local ip
+	if KUBE_CONFIG := os.Getenv("KUBE_CONFIG"); KUBE_CONFIG != "" {
+		KubeConfig = KUBE_CONFIG
+	} else {
+		usr, err := user.Current()
+		if err != nil {
+			panic("Failed to get current user info: " + err.Error())
+		} else {
+			KubeConfig = usr.HomeDir + "/" + ".kube/config"
+		}
+	}
+
+	if PILOT_ADDR := os.Getenv("PILOT_ADDR"); PILOT_ADDR != "" {
+		ValidPilotAddr = PILOT_ADDR
+	} else {
+		// panic("PILOT_ADDR should be specified to pass the pilot address")
+		testutil.InitLocalPilotTestEnv(t)
+		ValidPilotAddr = util.MockPilotGrpcAddr
+	}
+
+	if INSTANCE_IP := os.Getenv("INSTANCE_IP"); INSTANCE_IP != "" {
+		LocalIPAddress = INSTANCE_IP
+	} else if LocalIPAddress = iputil.GetLocalIP(); LocalIPAddress == "" {
+		panic("Failed to get the local ip address, please check the network environment")
+	}
+
+	nodeInfo = &istioinfra.NodeInfo{
+		PodName:    TEST_POD_NAME,
+		Namespace:  NAMESPACE_DEFAULT,
+		InstanceIP: LocalIPAddress,
+	}
+
+	testXdsClient, err = istioinfra.NewXdsClient(ValidPilotAddr, nil, nodeInfo, KubeConfig)
+	if err != nil {
+		panic("Failed to prepare test, xds client creation failed: " + err.Error())
+	}
+}
+
+func TestNewCacheManager(t *testing.T) {
+	testCacheManager, err = NewCacheManager(testXdsClient)
+	if err != nil {
+		t.Errorf("Failed to create CacheManager: %s", err.Error())
+	}
+}
+
+// func TestAutoSync(t *testing.T) {
+//     testCacheManager.AutoSync()
+// }
+
+func TestPullImcroserviceInstance(t *testing.T) {
+	err = testCacheManager.pullMicroserviceInstance()
+	if err != nil {
+		t.Errorf("Failed to pull microservice instances: %s", err.Error())
+	}
+}
+
+// func TestMakeIPIndex(t *testing.T) {
+//     err := testCacheManager.MakeIPIndex()
+//     if err != nil {
+//         t.Errorf("Failed to make ip index: %s", err.Error())
+//     }
+// }
+
+func TestEndpointCache(t *testing.T) {
+	ec := EndpointCache{
+		cache: map[string]EndpointSubset{},
+	}
+
+	subset := EndpointSubset{
+		subsetName: "foo",
+		tags:       map[string]string{},
+		instances:  []*registry.MicroServiceInstance{},
+	}
+
+	defer func() {
+		if r := recover(); r != nil {
+			t.Error("should not panic")
+		}
+	}()
+
+	waitChannel := make(chan int)
+	for i := 0; i < 1000; i++ {
+		go func() {
+			ec.Set("foo", subset)
+			waitChannel <- 0
+
+		}()
+	}
+
+	for i := 0; i < 1000; i++ {
+		<-waitChannel
+	}
+}
diff --git a/plugins/registry/istiov2/registry.go b/plugins/registry/istiov2/registry.go
new file mode 100644
index 0000000..624dffc
--- /dev/null
+++ b/plugins/registry/istiov2/registry.go
@@ -0,0 +1,243 @@
+package istiov2
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"strconv"
+	"strings"
+
+	apiv2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
+	apiv2endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
+	istioinfra "github.com/go-mesh/mesher/pkg/infras/istio"
+
+	"github.com/go-chassis/go-chassis/core/common"
+	"github.com/go-chassis/go-chassis/core/metadata"
+	"github.com/go-chassis/go-chassis/core/registry"
+	"github.com/go-chassis/go-chassis/pkg/util/iputil"
+	"github.com/go-chassis/go-chassis/pkg/util/tags"
+	"github.com/go-mesh/openlogging"
+)
+
+var (
+	//PodName is the name of the pod that mesher runs in
+	PodName string
+	//PodNamespace is the namespace which the pod belongs to
+	PodNamespace string
+	//InstanceIP is the IP of the pod(the IP of the first network adaptor)
+	InstanceIP string
+)
+
+const (
+	PilotV2Registry = "pilotv2"
+)
+
+//ServiceDiscovery is the discovery service for istio pilot with xDS v2 API
+type ServiceDiscovery struct {
+	Name    string
+	client  *istioinfra.XdsClient
+	options registry.Options
+}
+
+//GetMicroServiceID returns the id of the micro service
+func (discovery *ServiceDiscovery) GetMicroServiceID(appID, microServiceName, version, env string) (string, error) {
+	return microServiceName, nil
+}
+
+//GetAllMicroServices returns all the micro services, which is mapped from xDS clusters
+func (discovery *ServiceDiscovery) GetAllMicroServices() ([]*registry.MicroService, error) {
+	clusters, err := discovery.client.CDS()
+	if err != nil {
+		return nil, err
+	}
+	microServices := []*registry.MicroService{}
+	for _, cluster := range clusters {
+		microServices = append(microServices, toMicroService(&cluster))
+	}
+	return microServices, nil
+}
+
+func toMicroService(cluster *apiv2.Cluster) *registry.MicroService {
+	svc := &registry.MicroService{}
+	svc.ServiceID = cluster.Name
+	svc.ServiceName = cluster.Name
+	svc.Version = common.DefaultVersion
+	svc.AppID = common.DefaultApp
+	svc.Level = "BACK"
+	svc.Status = "UP"
+	svc.Framework = &registry.Framework{
+		Name:    "Istio",
+		Version: common.LatestVersion,
+	}
+	svc.RegisterBy = metadata.PlatformRegistrationComponent
+
+	return svc
+}
+
+func toMicroServiceInstance(clusterName string, lbendpoint *apiv2endpoint.LbEndpoint, tags map[string]string) *registry.MicroServiceInstance {
+	socketAddress := lbendpoint.Endpoint.Address.GetSocketAddress()
+	addr := socketAddress.Address
+	port := socketAddress.GetPortValue()
+	portStr := strconv.FormatUint(uint64(port), 10)
+	msi := &registry.MicroServiceInstance{}
+	msi.InstanceID = addr + "_" + portStr
+	msi.HostName = clusterName
+	msi.DefaultEndpoint = addr + ":" + portStr
+	msi.EndpointsMap = map[string]string{
+		common.ProtocolRest: msi.DefaultEndpoint,
+	}
+	msi.DefaultProtocol = common.ProtocolRest
+	msi.Metadata = tags
+
+	return msi
+}
+
+//GetMicroService returns the micro service info
+func (discovery *ServiceDiscovery) GetMicroService(microServiceID string) (*registry.MicroService, error) {
+	// If the service is in the clusters, return it, or nil
+
+	clusters, err := discovery.client.CDS()
+	if err != nil {
+		return nil, err
+	}
+
+	var targetCluster apiv2.Cluster
+	for _, cluster := range clusters {
+		parts := strings.Split(cluster.Name, "|")
+		if len(parts) < 4 {
+			openlogging.GetLogger().Warnf("Invalid cluster name: %s", cluster.Name)
+			continue
+		}
+
+		svcName := parts[3]
+		if strings.Index(svcName, microServiceID+".") == 0 {
+			targetCluster = cluster
+			break
+		}
+	}
+
+	if &targetCluster == nil {
+		return nil, nil
+	}
+
+	return toMicroService(&targetCluster), nil
+}
+
+//GetMicroServiceInstances returns the instances of the micro service
+func (discovery *ServiceDiscovery) GetMicroServiceInstances(consumerID, providerID string) ([]*registry.MicroServiceInstance, error) {
+	// TODO Handle the registry.MicroserviceIndex cache
+	// TODO Handle the microServiceName
+	service, err := discovery.GetMicroService(providerID)
+	if err != nil {
+		return nil, err
+	}
+
+	loadAssignment, err := discovery.client.EDS(service.ServiceName)
+	if err != nil {
+		return nil, err
+	}
+
+	instances := []*registry.MicroServiceInstance{}
+	endpionts := loadAssignment.Endpoints
+	for _, item := range endpionts {
+		for _, lbendpoint := range item.LbEndpoints {
+			msi := toMicroServiceInstance(loadAssignment.ClusterName, &lbendpoint, nil) // The cluster without subset doesn't have tags
+			instances = append(instances, msi)
+		}
+	}
+
+	return instances, nil
+}
+
+//FindMicroServiceInstances returns the micro service's instances filtered with tags
+func (discovery *ServiceDiscovery) FindMicroServiceInstances(consumerID, microServiceName string, tags utiltags.Tags) ([]*registry.MicroServiceInstance, error) {
+	if tags.KV == nil || tags.Label == "" { // Chassis might pass an empty tags
+		return discovery.GetMicroServiceInstances(consumerID, microServiceName)
+	}
+
+	instances := simpleCache.GetWithTags(microServiceName, tags.KV)
+	if len(instances) == 0 {
+		var lbendpoints []apiv2endpoint.LbEndpoint
+		var err error
+		lbendpoints, clusterName, err := discovery.client.GetEndpointsByTags(microServiceName, tags.KV)
+		if err != nil {
+			return nil, err
+		}
+
+		updateInstanceIndexCache(lbendpoints, clusterName, tags.KV)
+
+		instances = simpleCache.GetWithTags(microServiceName, tags.KV)
+		if instances == nil {
+			return nil, fmt.Errorf("Failed to find microservice instances of %s from cache", microServiceName)
+		}
+	}
+	return instances, nil
+}
+
+var cacheManager *CacheManager
+
+//AutoSync updates the services' info periodically in the background
+func (discovery *ServiceDiscovery) AutoSync() {
+	var err error
+	cacheManager, err = NewCacheManager(discovery.client)
+	if err != nil {
+		openlogging.GetLogger().Errorf("Failed to create cache manager, indexing will not work: %s", err.Error())
+	} else {
+		cacheManager.AutoSync()
+	}
+}
+
+//Close closes the discovery service
+func (discovery *ServiceDiscovery) Close() error {
+	return nil
+}
+
+//NewDiscoveryService creates the new ServiceDiscovery instance
+func NewDiscoveryService(options registry.Options) registry.ServiceDiscovery {
+	if len(options.Addrs) == 0 {
+		panic("Failed to create discovery service: Address not specified")
+	}
+	pilotAddr := options.Addrs[0]
+	nodeInfo := &istioinfra.NodeInfo{
+		PodName:    PodName,
+		Namespace:  PodNamespace,
+		InstanceIP: InstanceIP,
+	}
+	xdsClient, err := istioinfra.NewXdsClient(pilotAddr, options.TLSConfig, nodeInfo, options.ConfigPath)
+	if err != nil {
+		panic("Failed to create XDS client: " + err.Error())
+	}
+
+	discovery := &ServiceDiscovery{
+		client:  xdsClient,
+		Name:    PilotV2Registry,
+		options: options,
+	}
+
+	return discovery
+}
+
+func init() {
+	// Init the node info
+	PodName = os.Getenv("POD_NAME")
+	PodNamespace = os.Getenv("POD_NAMESPACE")
+	InstanceIP = os.Getenv("INSTANCE_IP")
+
+	// TODO Handle the default value
+	if PodName == "" {
+		PodName = "pod_name_default"
+	}
+	if PodNamespace == "" {
+		PodNamespace = "default"
+	}
+	if InstanceIP == "" {
+		log.Println("[WARN] Env var INSTANCE_IP not set, try to get instance ip from local network, the service might not work properly.")
+		InstanceIP = iputil.GetLocalIP()
+		if InstanceIP == "" {
+			// Won't work without instance ip
+			panic("Failed to get instance ip")
+		}
+	}
+
+	registry.InstallServiceDiscovery(PilotV2Registry, NewDiscoveryService)
+}
diff --git a/plugins/registry/istiov2/registry_test.go b/plugins/registry/istiov2/registry_test.go
new file mode 100644
index 0000000..6bc0aca
--- /dev/null
+++ b/plugins/registry/istiov2/registry_test.go
@@ -0,0 +1,206 @@
+package istiov2
+
+import (
+	"os"
+	"strconv"
+	"testing"
+
+	apiv2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
+	apiv2core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
+	apiv2endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
+	istioinfra "github.com/go-mesh/mesher/pkg/infras/istio"
+
+	"github.com/go-chassis/go-chassis/core/registry"
+	"github.com/go-chassis/go-chassis/pkg/util/tags"
+)
+
+var VaildServiceDiscovery registry.ServiceDiscovery
+var AllServices []*registry.MicroService
+
+func TestNewDiscoveryService(t *testing.T) {
+	options := registry.Options{
+		Addrs:      []string{ValidPilotAddr},
+		ConfigPath: KubeConfig,
+	}
+
+	// Explicitly set the env vars, though this is checkd in the init of cache_test
+	os.Setenv("POD_NAME", TEST_POD_NAME)
+	os.Setenv("NAMESPACE", NAMESPACE_DEFAULT)
+	os.Setenv("INSTANCE_IP", LocalIPAddress)
+
+	// No panic should happen
+	VaildServiceDiscovery = NewDiscoveryService(options)
+
+}
+
+// func TestAutoSync(t *testing.T) {
+//     archaius.Init()
+//     VaildServiceDiscovery.AutoSync()
+// }
+
+func TestEmptyPilotAddrs(t *testing.T) {
+	defer func() {
+		if err := recover(); err == nil {
+			t.Errorf("Panic should be caught")
+		}
+	}()
+
+	emptyAddrsOptions := registry.Options{
+		Addrs:      []string{},
+		ConfigPath: KubeConfig,
+	}
+	NewDiscoveryService(emptyAddrsOptions)
+}
+
+func TestGetAllMicroServices(t *testing.T) {
+	services, err := VaildServiceDiscovery.GetAllMicroServices()
+	if err != nil {
+		t.Errorf("Failed to get all micro services: %s", err.Error())
+	}
+
+	if len(services) == 0 {
+		t.Log("Warn: no micro services found")
+	}
+
+}
+
+func TestGetMicroServiceID(t *testing.T) {
+	serviceName := "pilotv2server"
+	msID, err := VaildServiceDiscovery.GetMicroServiceID("default", serviceName, "v3", "")
+	if err != nil {
+		t.Errorf("Failed to get micro service id: %s", err.Error())
+	}
+
+	if msID != serviceName {
+		t.Errorf("In pilotv2 discovery, msID should be equal to serviceName(%s != %s)", msID, serviceName)
+	}
+}
+
+func TestGetMicroService(t *testing.T) {
+	serviceName := "istio-pilot"
+	svc, err := VaildServiceDiscovery.GetMicroService(serviceName)
+	if err != nil {
+		t.Errorf("Failed to get micro service: %s", err.Error())
+	}
+	if svc == nil {
+		t.Errorf("istio-pilot service should not be nil")
+	}
+}
+
+func TestGetMicroServiceInstance(t *testing.T) {
+	// serviceName := "istio-pilot"
+	serviceName := "hello"
+	instances, err := VaildServiceDiscovery.GetMicroServiceInstances("pilotv2client", serviceName)
+	if err != nil {
+		t.Errorf("Failed to get micro service instances of istio-pilot: %s", err.Error())
+	}
+	if len(instances) == 0 {
+		t.Errorf("istio-pilot's instances should not be empty")
+	}
+}
+
+func TestFindMicroServiceInstances(t *testing.T) {
+	discovery, ok := VaildServiceDiscovery.(*ServiceDiscovery)
+	if !ok {
+		t.Errorf("Failed to convert discovery into type istiov2.ServiceDiscovery")
+		return
+	}
+	client := discovery.client
+
+	clusters, err := client.CDS()
+	if err != nil {
+		t.Errorf("Failed to teset FindMicroServiceInstances, CDS failed: %s", err.Error())
+	}
+
+	var clusterWithSubset *istioinfra.XdsClusterInfo = nil
+	for _, c := range clusters {
+		if info := istioinfra.ParseClusterName(c.Name); info != nil && info.Subset != "" {
+			clusterWithSubset = info
+		}
+	}
+
+	if clusterWithSubset != nil {
+		// an empty tags will make sure target tag always match
+		emptyTags := utiltags.Tags{
+			KV:    map[string]string{},
+			Label: "",
+		}
+		instances, err := VaildServiceDiscovery.FindMicroServiceInstances("pilotv2client", clusterWithSubset.ServiceName, emptyTags)
+		if err != nil {
+			t.Errorf("Failed to FindMicroServiceInstances of %s: %s", clusterWithSubset.ServiceName, err.Error())
+		}
+		if len(instances) == 0 {
+			t.Logf("%s's service instances is empty\n", clusterWithSubset.ServiceName)
+			t.Logf("Pls check if the destinationrule and corresponding pod tags are matching")
+		}
+	} else if len(clusters) != 0 {
+		t.Log("No clusters are with subsets")
+		targetCluster := clusters[0]
+
+		tags := utiltags.Tags{
+			KV: map[string]string{
+				"version": "v1",
+			},
+			Label: "version=v1",
+		}
+		_, err := VaildServiceDiscovery.FindMicroServiceInstances("pilotv2client", targetCluster.Name, tags)
+		if err == nil {
+			t.Errorf("Should caught error to get the endpoints of cluster without tags")
+		}
+	}
+
+}
+
+func TestToMicroService(t *testing.T) {
+	cluster := &apiv2.Cluster{
+		Name: "pilotv2server",
+	}
+
+	svc := toMicroService(cluster)
+
+	if svc.ServiceID != cluster.Name {
+		t.Errorf("service id should be equal to cluster name(%s != %s)", svc.ServiceID, cluster.Name)
+	}
+}
+
+func TestToMicroServiceInstance(t *testing.T) {
+	lbendpoint := &apiv2endpoint.LbEndpoint{
+		Endpoint: &apiv2endpoint.Endpoint{
+			Address: &apiv2core.Address{
+				Address: &apiv2core.Address_SocketAddress{
+					SocketAddress: &apiv2core.SocketAddress{
+						Address: "192.168.0.10:8822",
+					},
+				},
+			},
+		},
+	}
+	clusterName := "pilotv2server"
+	tags := map[string]string{
+		"version": "v1",
+	}
+	msi := toMicroServiceInstance(clusterName, lbendpoint, tags)
+
+	socketAddr := lbendpoint.Endpoint.Address.GetSocketAddress()
+	addr := socketAddr.GetAddress()
+	port := socketAddr.GetPortValue()
+
+	if msi.InstanceID != addr+"_"+strconv.FormatUint(uint64(port), 10) {
+		t.Errorf("Invalid msi.InstanceID: %s should be equal to %s_%d", msi.InstanceID, addr, port)
+	}
+
+	if msi.HostName != clusterName {
+		t.Errorf("Invalid msi.HostName: %s should be equal to %s", msi.HostName, clusterName)
+	}
+
+	// Test if the tags match
+	if !tagsMatch(tags, msi.Metadata) {
+		t.Errorf("Tags not match, %v should be subset of %s", tags, msi.Metadata)
+	}
+}
+
+func TestClose(t *testing.T) {
+	if err := VaildServiceDiscovery.Close(); err != nil {
+		t.Error(err)
+	}
+}
diff --git a/protocol/dubbo/proxy/dubbo_proxy_ouput.go b/protocol/dubbo/proxy/dubbo_proxy_ouput.go
index 6ee6e06..a1b026a 100755
--- a/protocol/dubbo/proxy/dubbo_proxy_ouput.go
+++ b/protocol/dubbo/proxy/dubbo_proxy_ouput.go
@@ -24,14 +24,6 @@
 	"net/http"
 	"net/url"
 
-	mesherCommon "github.com/go-mesh/mesher/common"
-	"github.com/go-mesh/mesher/config"
-	"github.com/go-mesh/mesher/protocol/dubbo/client"
-	"github.com/go-mesh/mesher/protocol/dubbo/dubbo"
-	"github.com/go-mesh/mesher/protocol/dubbo/schema"
-	"github.com/go-mesh/mesher/protocol/dubbo/utils"
-	"github.com/go-mesh/mesher/resolver"
-
 	"github.com/go-chassis/go-chassis/client/rest"
 	"github.com/go-chassis/go-chassis/core/common"
 	chassisconfig "github.com/go-chassis/go-chassis/core/config"
@@ -43,7 +35,14 @@
 	"github.com/go-chassis/go-chassis/pkg/runtime"
 	"github.com/go-chassis/go-chassis/pkg/util/tags"
 	"github.com/go-chassis/go-chassis/third_party/forked/afex/hystrix-go/hystrix"
+	mesherCommon "github.com/go-mesh/mesher/common"
+	mesherRuntime "github.com/go-mesh/mesher/pkg/runtime"
 	"github.com/go-mesh/mesher/protocol"
+	"github.com/go-mesh/mesher/protocol/dubbo/client"
+	"github.com/go-mesh/mesher/protocol/dubbo/dubbo"
+	"github.com/go-mesh/mesher/protocol/dubbo/schema"
+	"github.com/go-mesh/mesher/protocol/dubbo/utils"
+	"github.com/go-mesh/mesher/resolver"
 )
 
 var dr = resolver.GetDestinationResolver("http")
@@ -197,7 +196,7 @@
 			ctx.Req.SetAttachment(common.HeaderSourceName, chassisconfig.SelfServiceName)
 			ctx.Req.SetAttachment(ProxyTag, "true")
 
-			if config.Mode == mesherCommon.ModeSidecar {
+			if mesherRuntime.Mode == mesherCommon.ModeSidecar {
 				c, err = handler.GetChain(common.Consumer, mesherCommon.ChainConsumerOutgoing)
 				if err != nil {
 					lager.Logger.Error("Get Consumer chain failed: " + err.Error())
@@ -303,7 +302,7 @@
 		return err
 	}
 
-	if config.Mode == mesherCommon.ModeSidecar {
+	if mesherRuntime.Mode == mesherCommon.ModeSidecar {
 		c, err = handler.GetChain(common.Consumer, mesherCommon.ChainConsumerOutgoing)
 		if err != nil {
 			lager.Logger.Error("Get chain failed: " + err.Error())
diff --git a/protocol/grpc/server.go b/protocol/grpc/server.go
index ab0e2e9..00cc4dc 100755
--- a/protocol/grpc/server.go
+++ b/protocol/grpc/server.go
@@ -22,7 +22,6 @@
 	"errors"
 	"fmt"
 	"github.com/go-mesh/mesher/common"
-	"github.com/go-mesh/mesher/config"
 	"github.com/go-mesh/mesher/resolver"
 	"net"
 	"strings"
@@ -32,6 +31,7 @@
 	"github.com/go-chassis/go-chassis/core/lager"
 	"github.com/go-chassis/go-chassis/core/server"
 	chassisTLS "github.com/go-chassis/go-chassis/core/tls"
+	"github.com/go-mesh/mesher/pkg/runtime"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
 )
@@ -72,7 +72,7 @@
 		return fmt.Errorf("only support ipv4, input is [%s]", hs.opts.Address)
 	}
 
-	switch config.Mode {
+	switch runtime.Mode {
 	case common.ModeSidecar:
 		err = hs.startSidecar(host, port)
 	case common.ModePerHost:
diff --git a/protocol/http/http_server.go b/protocol/http/http_server.go
index e830c88..d6dbda0 100644
--- a/protocol/http/http_server.go
+++ b/protocol/http/http_server.go
@@ -34,6 +34,7 @@
 	"github.com/go-chassis/go-chassis/core/lager"
 	"github.com/go-chassis/go-chassis/core/server"
 	chassisTLS "github.com/go-chassis/go-chassis/core/tls"
+	"github.com/go-mesh/mesher/pkg/runtime"
 )
 
 const (
@@ -72,7 +73,7 @@
 		return fmt.Errorf("only support ipv4, input is [%s]", hs.opts.Address)
 	}
 
-	switch config.Mode {
+	switch runtime.Mode {
 	case common.ModeSidecar:
 		err = hs.startSidecar(host, port)
 	case common.ModePerHost:
diff --git a/protocol/http/reverse_proxy.go b/protocol/http/reverse_proxy.go
index 1b280d6..2e708c0 100755
--- a/protocol/http/reverse_proxy.go
+++ b/protocol/http/reverse_proxy.go
@@ -39,7 +39,7 @@
 	"github.com/go-chassis/go-chassis/third_party/forked/afex/hystrix-go/hystrix"
 	"github.com/go-mesh/mesher/cmd"
 	"github.com/go-mesh/mesher/common"
-	"github.com/go-mesh/mesher/metrics"
+	"github.com/go-mesh/mesher/pkg/metrics"
 	"github.com/go-mesh/mesher/protocol"
 	"github.com/go-mesh/mesher/resolver"
 )
@@ -74,8 +74,7 @@
 func consumerPreHandler(req *http.Request) *invocation.Invocation {
 	inv := preHandler(req)
 	inv.SourceServiceID = runtime.ServiceID
-	inv.SourceMicroService = chassisconfig.SelfServiceName
-	req.Header.Set(chassisCommon.HeaderSourceName, inv.SourceMicroService)
+	req.Header.Set(chassisCommon.HeaderSourceName, runtime.ServiceName)
 	inv.Ctx = context.TODO()
 	return inv
 }
@@ -121,8 +120,8 @@
 	}
 	defer func(begin time.Time) {
 		timeTaken := time.Since(begin).Seconds()
-		serviceLabelValues := map[string]string{metrics.ServiceName: inv.MicroServiceName, metrics.AppID: inv.RouteTags.AppID(), metrics.Version: inv.RouteTags.Version()}
-		metrics.DefaultPrometheusExporter.Summary(metrics.RequestLatencySeconds, timeTaken, metrics.LabelNames, serviceLabelValues)
+		serviceLabelValues := map[string]string{metrics.LServiceName: inv.MicroServiceName, metrics.LApp: inv.RouteTags.AppID(), metrics.LVersion: inv.RouteTags.Version()}
+		metrics.RecordLatency(serviceLabelValues, timeTaken, nil)
 	}(time.Now())
 	var invRsp *invocation.Response
 	c.Next(inv, func(ir *invocation.Response) error {
@@ -138,7 +137,7 @@
 		lager.Logger.Error("Handle request failed: " + err.Error())
 		return
 	}
-	metrics.RecordResponse(inv, resp.GetStatusCode())
+	RecordStatus(inv, resp.GetStatusCode())
 }
 
 //RemoteRequestHandler is for request from remote
@@ -237,7 +236,7 @@
 							return nil, ir.Err
 						}
 						copyChassisResp2HttpResp(w, resp)
-						metrics.RecordResponse(inv, resp.Resp.StatusCode)
+						RecordStatus(inv, resp.Resp.StatusCode)
 					} else {
 						// unknown error, resp is nil, e.g. connection refused
 						handleErrorResponse(inv, w, http.StatusBadGateway, ir.Err)
@@ -283,9 +282,14 @@
 	if err != nil {
 		w.Write([]byte(err.Error()))
 	}
-	metrics.RecordResponse(inv, statusCode)
+	RecordStatus(inv, statusCode)
 }
 
+//RecordStatus record an operation status
+func RecordStatus(inv *invocation.Invocation, statusCode int) {
+	LabelValues := map[string]string{metrics.LServiceName: inv.MicroServiceName, metrics.LApp: inv.RouteTags.AppID(), metrics.LVersion: inv.RouteTags.Version()}
+	metrics.RecordStatus(LabelValues, statusCode, nil)
+}
 func copyHeader(dst, src http.Header) {
 	for k, vs := range src {
 		for _, v := range vs {
diff --git a/resolver/log/chassis.log b/resolver/log/chassis.log
deleted file mode 100755
index e69de29..0000000
--- a/resolver/log/chassis.log
+++ /dev/null
diff --git a/scripts/build/build.sh b/scripts/build/build.sh
index 4364edd..af806f6 100644
--- a/scripts/build/build.sh
+++ b/scripts/build/build.sh
@@ -3,17 +3,24 @@
 set -x
 export PATH=$PATH:/usr/local/go/bin
 export GOPATH=/var/lib/jenkins/workspace/Mesher
-rm -rf /var/lib/jenkins/workspace/Mesher
+rm -rf /var/lib/jenkins/workspace/Mesher/src
 export BUILD_DIR=/var/lib/jenkins/workspace/Mesher
 export PROJECT_DIR=$(dirname $BUILD_DIR)
 
-mkdir -p /var/lib/jenkins/workspace/Mesher/src/github.com/go-chassis/mesher
+mkdir -p /var/lib/jenkins/workspace/Mesher/src/github.com/go-mesh/mesher
 
-cp -r /var/lib/jenkins/workspace/mesher/* /var/lib/jenkins/workspace/Mesher/src/github.com/go-chassis/mesher/
+#To checkout to particular commit or tag
+if [ $CHECKOUT_VERSION == "latest" ]; then
+    echo "using latest code"
+else
+    git checkout $CHECKOUT_VERSION
+fi
+
+cp -r /var/lib/jenkins/workspace/mesher/* /var/lib/jenkins/workspace/Mesher/src/github.com/go-mesh/mesher/
 
 release_dir=$PROJECT_DIR/release
 repo="github.com"
-project="go-chassis"
+project="go-mesh"
 
 if [ -d $release_dir ]; then
     rm -rf $release_dir
@@ -21,16 +28,16 @@
 mkdir -p $release_dir
 
 cd $BUILD_DIR/src/$repo/$project/mesher
-#To checkout to particular commit or tag
-if [ $CHECKOUT_VERSION == "latest" ]; then
-    echo "using latest code"
-else
-    git checkout $CHECKOUT_VERSION
-fi
+
 GO111MODULE=on go mod download
 GO111MODULE=on go mod vendor
 go build -o mesher -a
 
+if [ $VERSION != "latest" ]; then
+    cd $PROJECT_DIR/mesher
+    git tag -a $TAG_VERSION -m "$TAG_MESSAGE"
+    git push origin $TAG_VERSION
+fi
 
 export WORK_DIR=$BUILD_DIR/src/$repo/$project/mesher
 
@@ -66,5 +73,12 @@
 if [ $JOB_NAME != "" ]; then
     cp $release_dir/$pkg_name /var/lib/jenkins/mesher-release
 fi
+
+if [ $VERSION != "latest" ]; then
+    date=$(date +%Y-%m-%d)
+    DIR_NAME="mesher-release-$date"
+    mkdir -p /var/lib/jenkins/userContent/mesher-release/$DIR_NAME
+    cp $release_dir/$pkg_name /var/lib/jenkins/userContent/mesher-release/$DIR_NAME
+fi
 tar zcvf $WORK_DIR/mesher.tar.gz licenses conf start.sh mesher VERSION
 exit 0
diff --git a/scripts/build/build_image.sh b/scripts/build/build_image.sh
index 7779ccd..5d5f6ca 100644
--- a/scripts/build/build_image.sh
+++ b/scripts/build/build_image.sh
@@ -2,24 +2,24 @@
 set -e
 set -x
 
-cd /var/lib/jenkins/workspace/Mesher/src/github.com/go-chassis/mesher/
+cd /var/lib/jenkins/workspace/Mesher/src/github.com/go-mesh/mesher/
 
 repo="github.com"
-project="go-chassis"
+project="go-mesh"
 export BUILD_DIR=/var/lib/jenkins/workspace/Mesher
 export WORK_DIR=$BUILD_DIR/src/$repo/$project/mesher
 cd $WORK_DIR
 
-docker build -t gochassis/mesher:$VERSION .
+docker build -t gomesh/mesher:$VERSION .
 
 cp /var/lib/jenkins/workspace/docker_login.sh .
 bash docker_login.sh &> /dev/null
 
 if [ $PUSH_WITH_LATEST_TAG == "YES" ]; then
-    docker build -t gochassis/mesher:latest .
-    docker push gochassis/mesher:latest
+    docker build -t gomesh/mesher:latest .
+    docker push gomesh/mesher:latest
 fi
 
-docker push gochassis/mesher:$VERSION
+docker push gomesh/mesher:$VERSION
 
 exit 0
diff --git a/scripts/travis/unit_test.sh b/scripts/travis/unit_test.sh
index 7e76a77..81d324b 100644
--- a/scripts/travis/unit_test.sh
+++ b/scripts/travis/unit_test.sh
@@ -9,7 +9,7 @@
     if [ $(ls | grep _test.go | wc -l) -gt 0 ]; then
         go test -cover -covermode atomic -coverprofile coverage.out
         if [ -f coverage.out ]; then
-            sed '1d;$d' coverage.out >> $GOPATH/src/github.com/go-chassis/mesher/coverage.txt
+            sed '1d;$d' coverage.out >> $GOPATH/src/github.com/go-mesh/mesher/coverage.txt
         fi
     fi
 done
\ No newline at end of file
diff --git a/start.sh b/start.sh
index b36ca9e..8880e73 100644
--- a/start.sh
+++ b/start.sh
@@ -101,6 +101,27 @@
 EOF
 fi
 
+#add instance_properties if any provided
+if [ ! -z "$MD" ]; then
+  echo "  instance_properties:" >> $MESHER_CONF_DIR/$MICROSERVICE_YAML
+  while : 
+  do
+    KeyArray=$(echo $MD | cut -d '|' -f1)
+    RestArray=$(echo $MD | cut -d '|' -f2-)
+    Writer="-"
+    Key=$(echo $KeyArray | cut -d '=' -f1)
+    Value=$(echo $KeyArray | cut -d '=' -f2-)
+    Writer="    $Writer$Key"
+    Writer="$Writer: $Value"
+    echo $Writer| sed 's/-/    /'
+    echo $Writer | sed 's/-/    /'>> $MESHER_CONF_DIR/$MICROSERVICE_YAML
+    if [ "$KeyArray" = "$RestArray" ]; then
+      break
+    fi
+    MD=$RestArray
+  done
+fi
+
 # ENABLE_PROXY_TLS decide whether mesher is https proxy or http proxy
 if [[ $TLS_ENABLE && $TLS_ENABLE == true ]]; then
     sed -i '/ssl:/a \ \ mesher.Provider.cipherPlugin: default \n \ mesher.Provider.verifyPeer: false \n \ mesher.Provider.cipherSuits: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 \n \ mesher.Provider.protocol: TLSv1.2 \n \ mesher.Provider.caFile: \n \ mesher.Provider.certFile: /etc/ssl/meshercert/kubecfg.crt \n \ mesher.Provider.keyFile: /etc/ssl/meshercert/kubecfg.key \n \ mesher.Provider.certPwdFile: \n' $MESHER_CONF_DIR/$TLS_YAML
diff --git a/test/conf/auth.yaml b/test/conf/auth.yaml
deleted file mode 100644
index 56d7e02..0000000
--- a/test/conf/auth.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-## Huawei Public Cloud ak/sk
-cse:
-  credentials:
-    accessKey:
-    secretKey:
-    project:
-    akskCustomCipher: default #used to decrypt sk when it is encrypted
diff --git a/test/conf/chassis.yaml b/test/conf/chassis.yaml
deleted file mode 100644
index 1d72915..0000000
--- a/test/conf/chassis.yaml
+++ /dev/null
@@ -1,114 +0,0 @@
----
-cse:
-  protocols:
-    grpc:
-      listenAddress: 10.0.2.15:40105
-    http:
-      listenAddress: 10.0.2.15:30105
-  service:
-    registry:
-      address: http://127.0.0.1:30100 # uri of service center
-      #address: https://cse.cn-north-1.myhuaweicloud.com:443 # uri of service center
-      scope: full #set full to be able to discover other app's service
-      watch: false # set if you want to watch instance change event
-      autoIPIndex: true # set to true if u want to resolve source IP to microservice
-#  config:
-#    client:
-#      serverUri: https://cse.cn-north-1.myhuaweicloud.com:443 #uri of config center
-#      refreshMode: 1 # 1: only pull config.
-#      refreshInterval: 30 # unit is second
-#  monitor: #Send monitoring data to CSE monitor Server
-#    client:
-#      serverUri: https://cse.cn-north-1.myhuaweicloud.com:443   # monitor server url
-  handler:
-    chain:
-      Consumer:
-        outgoing:  #consumer handlers
-      Provider:
-        incoming:  #provider handlers
-#  loadbalance:
-#    strategy:
-#      name: RoundRobin  # Random|RoundRobin|SessionStickiness
-#    retryEnabled: false # if there is error, retry request or not
-#    retryOnNext: 2      # times to switch to another instance based on strategy
-#    retryOnSame: 3      # times to retry on the same instance
-#    backoff:            # backoff policy of retried request
-#      kind: constant    # jittered/constant/zero
-#      MinMs: 200        # millisecond, Minimum duration to backoff
-#      MaxMs: 400        # millisecond, Maximum duration to backoff
-## circuit breaker configurations
-#  isolation:
-#    Consumer:
-#      timeout:
-#        enabled: true
-#      timeoutInMilliseconds: 1000
-#      maxConcurrentRequests: 100
-#  circuitBreaker:
-#    Consumer:
-#      enabled: true
-#      forceOpen: false
-#      forceClosed: false
-#      sleepWindowInMilliseconds: 10000
-#      requestVolumeThreshold: 20
-#      errorThresholdPercentage: 50
-#  fallback:
-#    Consumer:
-#      enabled: true
-#      maxConcurrentRequests: 20
-#  fallbackpolicy:
-#    Consumer:
-#      policy: throwexception
-#  flowcontrol:
-#    Consumer: # for consumer
-#      qps:
-#        enabled: true  # enable rate limiting or not
-#        global:
-#          limit: 100   # default limit of consumer
-#        limit:
-#          Server: 100  # rate limit for request to a provider,it represents 100 request per second
-#    Provider:
-#      qps:
-#        enabled: true  # enable rate limiting or not
-#        global:
-#          limit: 100   # default limit of provider
-#        limit:
-#          Server: 100  # rate limit for request from a provider, it represents 100 request per second
-
-#ssl:
-## Set those config to make mesher as https service
-#  mesher.Provider.cipherPlugin: default
-#  mesher.Provider.verifyPeer: false
-#  mesher.Provider.cipherSuits: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
-#  mesher.Provider.protocol: TLSv1.2
-#  mesher.Provider.caFile:
-#  mesher.Provider.certFile:
-#  mesher.Provider.keyFile:
-#  mesher.Provider.certPwdFile:
-## Mesher TLS is base on Go Chassis TLS config
-## If users wan't to use transparent, ssl config for consumer and provider must be supplied.
-## The provider is the service which run in the same host/pod with mesher. for example the service name of provider is AccountService, then the ssl tag is AccountService.rest.Provider
-## if u set this , no need to consider about expose your own service as https service,
-## your service can only listen on 127.0.0.1, mesher wil expose https and use http to communicate with your service
-#  AccountService.rest.Provider.cipherPlugin: default
-#  AccountService.rest.Provider.verifyPeer: false
-#  AccountService.rest.Provider.cipherSuits: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
-#  AccountService.rest.Provider.protocol: TLSv1.2
-#  AccountService.rest.Provider.caFile:
-#  AccountService.rest.Provider.certFile:
-#  AccountService.rest.Provider.keyFile:
-#  AccountService.rest.Provider.certPwdFile:
-## If a service want to use transparent tls to call other services, it must supplies consumer ssl config for these services.
-## for example StoreWeb want to communicate with Account service the  config is like below
-#  AccountService.rest.Consumer.cipherPlugin: default
-#  AccountService.rest.Consumer.verifyPeer: false
-#  AccountService.rest.Consumer.cipherSuits: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
-#  AccountService.rest.Consumer.protocol: TLSv1.2
-#  AccountService.rest.Consumer.caFile:
-#  AccountService.rest.Consumer.certFile:
-#  AccountService.rest.Consumer.keyFile:
-#  AccountService.rest.Consumer.certPwdFile:
-#tracing:
-#  enabled: true #enable distribution tracing
-#  collectorType: zipkin       #zipkin: Send tracing info to zipkin server
-#                              #namedPipe: Write tracing info to linux named pipe.
-#  collectorTarget: http://localhost:9411/api/v1/spans #If the collectorType is "zipkin", the target is a zipkin server url, if the collecterType is "file" or "namedPipe", the target is a file path.
diff --git a/test/conf/fault.yaml b/test/conf/fault.yaml
deleted file mode 100644
index d55c9e7..0000000
--- a/test/conf/fault.yaml
+++ /dev/null
@@ -1,51 +0,0 @@
-#cse:
-#  governance:
-#    Consumer:
-#      _global: #最低优先级配置
-#        policy: #治理策略 包括fault,loadbalance,circuit breaker等等,目前只是新的fault加入,旧的治理可考虑慢慢增加支持
-#          fault: #
-#            protocols: # 向协议模块注入错误,考虑未来扩展多任意组件注入错误,所以这么设计
-#              rest:
-#                delay:
-#                  fixedDelay: 5
-#                  percent: 10
-#                abort:
-#                  httpStatus: 421
-#                  percent: 100
-#              highway:
-#                delay:
-#                  fixedDelay: 2
-#                  percent: 100
-#                abort:
-#                  percent: 30
-#      ms1:
-#        route: |
-#            - precedence: 2
-#              match:
-#                source: source.service
-#              traffic:
-#                - tags:
-#                    version: 1.0
-#                  weight: 90
-#                - tags:
-#                    version: 1.1
-#                  weight: 10
-#                  policy:
-#                    fault:
-#                    schemas:
-#                      sid1:
-#                        policy:
-#                          fault:
-#                        operations:
-#                          policy:
-#                            fault:
-#        policy: # 微服务名级别治理策略
-#          fault:
-#        schemas: #schema级别治理策略
-#          sid1:
-#            policy:
-#              fault:
-#            operations: #operation级别治理策略
-#              policy:
-#                fault:
-#    Provider: # format same as Consumer
\ No newline at end of file
diff --git a/test/conf/lager.yaml b/test/conf/lager.yaml
deleted file mode 100644
index 0634de4..0000000
--- a/test/conf/lager.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
----
-writers: file,stdout
-# LoggerLevel: |DEBUG|INFO|WARN|ERROR|FATAL
-logger_level: DEBUG
-
-# LoggerFile: used to output the name of log
-logger_file: log/mesher.log
-
-# LogFormatText: json/plaintext (such as log4j),default to false
-# if set logger_file and log_format_text to true, turns out log4j format log
-log_format_text: true
-
-#rollingPolicy daily/size; defines rotate according to daily or size
-rollingPolicy: size
-
-# MaxDaily of a log file before rotate. By D Days.
-log_rotate_date: 1
-
-# MaxSize of a log file before rotate. By M Bytes.
-log_rotate_size: 10
-
-# Max counts to keep of a log's backup files.
-log_backup_count: 7
\ No newline at end of file
diff --git a/test/conf/mesher.yaml b/test/conf/mesher.yaml
deleted file mode 100644
index a6eadeb..0000000
--- a/test/conf/mesher.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-## Router rules and fault injection rules are moved to router.yaml
-#plugin:
-#  destinationResolver:
-#    http: host # how to turn host to destination name. default to service name,
-
-##admin: #admin API
-#  serverUri : 127.0.0.1:30102 # addr on listening
-#  goRuntimeMetrics : true # enable metrics
-
-## enable pprof to profile mesher runtime
-#pprof:
-#  enable: false
-
-#localHealthCheck:
-#  - port: 8080
-#    uri: /health
-#    interval: 30s
-#    match:
-#      status: 200
-#      body: ok
diff --git a/test/conf/microservice.yaml b/test/conf/microservice.yaml
deleted file mode 100644
index c8356d8..0000000
--- a/test/conf/microservice.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-## microservice property
-service_description:
-  name: Server
-  version: 0.0.1
-  environment:  #microservice environment
-  properties:
-    allowCrossApp: false #whether to allow calls across applications
diff --git a/test/conf/router.yaml b/test/conf/router.yaml
deleted file mode 100644
index 1146860..0000000
--- a/test/conf/router.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-#routeRule:
-#  ShoppingCart:        #service name
-#    - precedence: 2    #precedence of route rule
-#      route:           #route rule list
-#      - tags:
-#          version: 0.2 
-#          app: HelloWorld 
-#        weight: 80     #weight of 80%
-#      - tags:
-#          version: 1.2
-#          app: HelloWorld
-#        weight: 20     #weight of 20%
\ No newline at end of file
diff --git a/test/log/mesher.log b/test/log/mesher.log
deleted file mode 100755
index b10fb48..0000000
--- a/test/log/mesher.log
+++ /dev/null
Binary files differ