Repository: argoproj/argo-rollouts
Pull request #416 (2020-02-26 19:13:29)

feat: Add metrics on queues and go client http calls
This PR adds metrics on the controller workqueues (i.e. queue depth, average queue waiting time) and go client http calls (i.e. updating a rollout or creating a ReplicaSet) 

codecov[bot]: # [Codecov](https://codecov.io/gh/argoproj/argo-rollouts/pull/416?src=pr&el=h1) Report
> Merging [#416](https://codecov.io/gh/argoproj/argo-rollouts/pull/416?src=pr&el=desc) into [master](https://codecov.io/gh/argoproj/argo-rollouts/commit/55f6fd89b949243fab58612f5f3c0e401e8caa81?src=pr&el=desc) will **increase** coverage by `0.21%`.
> The diff coverage is `93.6%`.

[![Impacted file tree graph](https://codecov.io/gh/argoproj/argo-rollouts/pull/416/graphs/tree.svg?width=650&token=FYYCEVzSoJ&height=150&src=pr)](https://codecov.io/gh/argoproj/argo-rollouts/pull/416?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #416      +/-   ##
==========================================
+ Coverage    84.5%   84.72%   +0.21%     
==========================================
  Files          70       73       +3     
  Lines        6667     6835     +168     
==========================================
+ Hits         5634     5791     +157     
- Misses        746      754       +8     
- Partials      287      290       +3
```


| [Impacted Files](https://codecov.io/gh/argoproj/argo-rollouts/pull/416?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [controller/metrics/metrics.go](https://codecov.io/gh/argoproj/argo-rollouts/pull/416/diff?src=pr&el=tree#diff-Y29udHJvbGxlci9tZXRyaWNzL21ldHJpY3MuZ28=) | `79.77% <100%> (+0.7%)` | :arrow_up: |
| [controller/metrics/client.go](https://codecov.io/gh/argoproj/argo-rollouts/pull/416/diff?src=pr&el=tree#diff-Y29udHJvbGxlci9tZXRyaWNzL2NsaWVudC5nbw==) | `100% <100%> (ø)` | |
| [utils/unstructured/unstructured.go](https://codecov.io/gh/argoproj/argo-rollouts/pull/416/diff?src=pr&el=tree#diff-dXRpbHMvdW5zdHJ1Y3R1cmVkL3Vuc3RydWN0dXJlZC5nbw==) | `100% <100%> (ø)` | |
| [utils/go-client/metric.go](https://codecov.io/gh/argoproj/argo-rollouts/pull/416/diff?src=pr&el=tree#diff-dXRpbHMvZ28tY2xpZW50L21ldHJpYy5nbw==) | `91.97% <91.97%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/argoproj/argo-rollouts/pull/416?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/argoproj/argo-rollouts/pull/416?src=pr&el=footer). Last update [55f6fd8...78e9d03](https://codecov.io/gh/argoproj/argo-rollouts/pull/416?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/Gopkg.lock b/Gopkg.lock
new file mode 100644
index 000000000..7c92f74ab
--- /dev/null
+++ b/Gopkg.lock
@@ -0,0 +1,1452 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  digest = "1:dd029f90457e0bc0fc4a549a241327bdcac1f2a36692041a19ef02aec4c36103"
+  name = "cloud.google.com/go"
+  packages = ["compute/metadata"]
+  pruneopts = ""
+  revision = "74b12019e2aa53ec27882158f59192d7cd6d1998"
+  version = "v0.33.1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:6978a38432a017763a148afbc7ce6491734b54292af7d3e969d84d2e9dd242e2"
+  name = "github.com/Azure/go-ansiterm"
+  packages = [
+    ".",
+    "winterm",
+  ]
+  pruneopts = ""
+  revision = "d6e3b3328b783f23731bc4d058875b0371ff8109"
+
+[[projects]]
+  digest = "1:63e57618d792cccb87ad7cb8a0602e6205732beb3b01b0ea858fc4a5fd3ce8f1"
+  name = "github.com/MakeNowJust/heredoc"
+  packages = ["."]
+  pruneopts = ""
+  revision = "efb6ca8de9d5385c3963279701760e37637cf238"
+  version = "v2.0.1"
+
+[[projects]]
+  digest = "1:8e47871087b94913898333f37af26732faaab30cdb41571136cf7aec9921dae7"
+  name = "github.com/PuerkitoBio/purell"
+  packages = ["."]
+  pruneopts = ""
+  revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
+  version = "v1.1.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:331a419049c2be691e5ba1d24342fc77c7e767a80c666a18fd8a9f7b82419c1c"
+  name = "github.com/PuerkitoBio/urlesc"
+  packages = ["."]
+  pruneopts = ""
+  revision = "de5bf2ad457846296e2031421a34e2568e304e35"
+
+[[projects]]
+  branch = "master"
+  digest = "1:a7f619ffc7b99687f9444bd0a07509fec8ae708a7175d234878129896c0918a8"
+  name = "github.com/alecthomas/template"
+  packages = [
+    ".",
+    "parse",
+  ]
+  pruneopts = ""
+  revision = "fb15b899a75114aa79cc930e33c46b577cc664b1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:9d943843b71c5d44f184893fcdbe419bf639fee8647ceeca4c7d4fd95923721c"
+  name = "github.com/alecthomas/units"
+  packages = ["."]
+  pruneopts = ""
+  revision = "f65c72e2690dc4b403c8bd637baf4611cd4c069b"
+
+[[projects]]
+  digest = "1:d006584293547a5a28116ac4e02e250a07911e59b3db7fb1b7ab93c25721cdcb"
+  name = "github.com/antlr/antlr4"
+  packages = ["runtime/Go/antlr"]
+  pruneopts = ""
+  revision = "be58ebffde8e29c154192c019608f0a5b8e6a064"
+  version = "4.7.2"
+
+[[projects]]
+  digest = "1:3fbdd1c39fb005519b1cb4a58723527614d78368868bb7e24a45526e2d5f1740"
+  name = "github.com/antonmedv/expr"
+  packages = [
+    ".",
+    "ast",
+    "checker",
+    "compiler",
+    "internal/conf",
+    "internal/file",
+    "optimizer",
+    "parser",
+    "parser/gen",
+    "vm",
+  ]
+  pruneopts = ""
+  revision = "4d40254bf70e2ba6f90dea9cc5d36e96336bbe84"
+  version = "v2.1.2"
+
+[[projects]]
+  branch = "master"
+  digest = "1:c0bec5f9b98d0bc872ff5e834fac186b807b656683bd29cb82fb207a1513fabb"
+  name = "github.com/beorn7/perks"
+  packages = ["quantile"]
+  pruneopts = ""
+  revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
+
+[[projects]]
+  digest = "1:a6ee710e45210bafe11f2f28963571be2ac8809f9a7b675a6d2c02302a1ce1a9"
+  name = "github.com/bouk/monkey"
+  packages = ["."]
+  pruneopts = ""
+  revision = "5df1f207ff77e025801505ae4d903133a0b4353f"
+  version = "v1.0.0"
+
+[[projects]]
+  digest = "1:0deddd908b6b4b768cfc272c16ee61e7088a60f7fe2f06c547bd3d8e1f8b8e77"
+  name = "github.com/davecgh/go-spew"
+  packages = ["spew"]
+  pruneopts = ""
+  revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
+  version = "v1.1.1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:7942de144228c1b62eaba44ec5153a29d25cd016e8fb23cb9533c77f6111b397"
+  name = "github.com/docker/distribution"
+  packages = [
+    "digestset",
+    "reference",
+  ]
+  pruneopts = ""
+  revision = "aa985ba8897a426e5db31b36cd8cca83cf85cead"
+
+[[projects]]
+  digest = "1:50a4629dd29d90473be834b7d6c502f310a269f06f31c069a8c6e2b4274a14b3"
+  name = "github.com/docker/docker"
+  packages = [
+    "pkg/term",
+    "pkg/term/windows",
+  ]
+  pruneopts = ""
+  revision = "be7ac8be2ae072032a4005e8f232be3fc57e4127"
+
+[[projects]]
+  branch = "master"
+  digest = "1:d6c13a378213e3de60445e49084b8a0a9ce582776dfc77927775dbeb3ff72a35"
+  name = "github.com/docker/spdystream"
+  packages = [
+    ".",
+    "spdy",
+  ]
+  pruneopts = ""
+  revision = "6480d4af844c189cf5dd913db24ddd339d3a4f85"
+
+[[projects]]
+  digest = "1:8a34d7a37b8f07239487752e14a5faafcbbc718fc385ad429a2c4ac6f27a207f"
+  name = "github.com/emicklei/go-restful"
+  packages = [
+    ".",
+    "log",
+  ]
+  pruneopts = ""
+  revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0"
+  version = "v2.8.0"
+
+[[projects]]
+  digest = "1:dcefbadf4534c5ecac8573698fba6e6e601157bfa8f96aafe29df31ae582ef2a"
+  name = "github.com/evanphx/json-patch"
+  packages = ["."]
+  pruneopts = ""
+  revision = "afac545df32f2287a079e2dfb7ba2745a643747e"
+  version = "v3.0.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:549f95037fea25e00a5341ac6a169a5b3e5306be107f45260440107b779b74f9"
+  name = "github.com/exponent-io/jsonpath"
+  packages = ["."]
+  pruneopts = ""
+  revision = "d6023ce2651d8eafb5c75bb0c7167536102ec9f5"
+
+[[projects]]
+  branch = "master"
+  digest = "1:ec95c1c49fbec27ab5383b9c47fae5c2fe1d97ac5b41d36d78e17588a44e9f3f"
+  name = "github.com/ghodss/yaml"
+  packages = ["."]
+  pruneopts = ""
+  revision = "25d852aebe32c875e9c044af3eef9c7dc6bc777f"
+
+[[projects]]
+  digest = "1:c8052dcf3ec378a9a6bc4f00ecc10d6d5eb3cc1f8faaf6b2f70f047e8881d446"
+  name = "github.com/go-openapi/jsonpointer"
+  packages = ["."]
+  pruneopts = ""
+  revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004"
+  version = "v0.18.0"
+
+[[projects]]
+  digest = "1:1824e5330b35b2a2418d06aa55629cc59ad454b72e338aa125ba8ff98f16298b"
+  name = "github.com/go-openapi/jsonreference"
+  packages = ["."]
+  pruneopts = ""
+  revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3"
+  version = "v0.18.0"
+
+[[projects]]
+  digest = "1:54af405aae840f810418f3d25211012af1c4bfd56d07d3de6482a7a3b762528a"
+  name = "github.com/go-openapi/spec"
+  packages = ["."]
+  pruneopts = ""
+  revision = "5b6cdde3200976e3ecceb2868706ee39b6aff3e4"
+  version = "v0.18.0"
+
+[[projects]]
+  digest = "1:417789264f7cc44cbb3431ac997473e085018b01bdd98df57e6039981428aca4"
+  name = "github.com/go-openapi/swag"
+  packages = ["."]
+  pruneopts = ""
+  revision = "1d29f06aebd59ccdf11ae04aa0334ded96e2d909"
+  version = "v0.18.0"
+
+[[projects]]
+  digest = "1:6e73003ecd35f4487a5e88270d3ca0a81bc80dc88053ac7e4dcfec5fba30d918"
+  name = "github.com/gogo/protobuf"
+  packages = [
+    "proto",
+    "sortkeys",
+  ]
+  pruneopts = ""
+  revision = "636bf0302bc95575d69441b25a2603156ffdddf1"
+  version = "v1.1.1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:aa2251148505e561bfa8cd6b69a319b37761da57b0b25529c4af08389559e3b9"
+  name = "github.com/golang/groupcache"
+  packages = ["lru"]
+  pruneopts = ""
+  revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa"
+
+[[projects]]
+  digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18"
+  name = "github.com/golang/protobuf"
+  packages = [
+    "proto",
+    "ptypes",
+    "ptypes/any",
+    "ptypes/duration",
+    "ptypes/timestamp",
+  ]
+  pruneopts = ""
+  revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
+  version = "v1.2.0"
+
+[[projects]]
+  digest = "1:1e5b1e14524ed08301977b7b8e10c719ed853cbf3f24ecb66fae783a46f207a6"
+  name = "github.com/google/btree"
+  packages = ["."]
+  pruneopts = ""
+  revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
+  version = "v1.0.0"
+
+[[projects]]
+  digest = "1:9fcb267c272bc5054564b392e3ff7e65e35400fd9914afb1d169f92b95e7dbc9"
+  name = "github.com/google/go-cmp"
+  packages = [
+    "cmp",
+    "cmp/internal/diff",
+    "cmp/internal/flags",
+    "cmp/internal/function",
+    "cmp/internal/value",
+  ]
+  pruneopts = ""
+  revision = "2d0692c2e9617365a95b295612ac0d4415ba4627"
+  version = "v0.3.1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:754f77e9c839b24778a4b64422236d38515301d2baeb63113aa3edc42e6af692"
+  name = "github.com/google/gofuzz"
+  packages = ["."]
+  pruneopts = ""
+  revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
+
+[[projects]]
+  digest = "1:a25a2c5ae694b01713fb6cd03c3b1ac1ccc1902b9f0a922680a88ec254f968e1"
+  name = "github.com/google/uuid"
+  packages = ["."]
+  pruneopts = ""
+  revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8"
+  version = "v1.1.0"
+
+[[projects]]
+  digest = "1:16b2837c8b3cf045fa2cdc82af0cf78b19582701394484ae76b2c3bc3c99ad73"
+  name = "github.com/googleapis/gnostic"
+  packages = [
+    "OpenAPIv2",
+    "compiler",
+    "extensions",
+  ]
+  pruneopts = ""
+  revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
+  version = "v0.2.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:e1fd67b5695fb12f54f979606c5d650a5aa72ef242f8e71072bfd4f7b5a141a0"
+  name = "github.com/gregjones/httpcache"
+  packages = [
+    ".",
+    "diskcache",
+  ]
+  pruneopts = ""
+  revision = "901d90724c7919163f472a9812253fb26761123d"
+
+[[projects]]
+  digest = "1:3313a63031ae281e5f6fd7b0bbca733dfa04d2429df86519e3b4d4c016ccb836"
+  name = "github.com/hashicorp/golang-lru"
+  packages = [
+    ".",
+    "simplelru",
+  ]
+  pruneopts = ""
+  revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768"
+  version = "v0.5.0"
+
+[[projects]]
+  digest = "1:7ab38c15bd21e056e3115c8b526d201eaf74e0308da9370997c6b3c187115d36"
+  name = "github.com/imdario/mergo"
+  packages = ["."]
+  pruneopts = ""
+  revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4"
+  version = "v0.3.6"
+
+[[projects]]
+  digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
+  name = "github.com/inconshreveable/mousetrap"
+  packages = ["."]
+  pruneopts = ""
+  revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
+  version = "v1.0"
+
+[[projects]]
+  digest = "1:b79fc583e4dc7055ed86742e22164ac41bf8c0940722dbcb600f1a3ace1a8cb5"
+  name = "github.com/json-iterator/go"
+  packages = ["."]
+  pruneopts = ""
+  revision = "1624edc4454b8682399def8740d46db5e4362ba4"
+  version = "v1.1.5"
+
+[[projects]]
+  branch = "master"
+  digest = "1:14a9763035ddd561bd2434463ff342a5cec5fd94730d2bd33d21a14714ee57e1"
+  name = "github.com/juju/ansiterm"
+  packages = [
+    ".",
+    "tabwriter",
+  ]
+  pruneopts = ""
+  revision = "720a0952cc2ac777afc295d9861263e2a4cf96a1"
+
+[[projects]]
+  digest = "1:6a874e3ddfb9db2b42bd8c85b6875407c702fa868eed20634ff489bc896ccfd3"
+  name = "github.com/konsorten/go-windows-terminal-sequences"
+  packages = ["."]
+  pruneopts = ""
+  revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
+  version = "v1.0.1"
+
+[[projects]]
+  digest = "1:b60ba8f16c4bd2c27ddab8c95f045d1275df450b28d0d95513a9e70c8ae9910c"
+  name = "github.com/lunixbochs/vtclean"
+  packages = ["."]
+  pruneopts = ""
+  revision = "88cfb0c2efe8ed7b0ccf0af83db39359829027bb"
+  version = "v1.0.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:212bebc561f4f654a653225868b2a97353cd5e160dc0b0bbc7232b06608474ec"
+  name = "github.com/mailru/easyjson"
+  packages = [
+    "buffer",
+    "jlexer",
+    "jwriter",
+  ]
+  pruneopts = ""
+  revision = "60711f1a8329503b04e1c88535f419d0bb440bff"
+
+[[projects]]
+  digest = "1:9b58ad18b38cf0d44b1d006fce319e45f200eafa406fe7f65fe0d0194b9f7a9f"
+  name = "github.com/mattn/go-colorable"
+  packages = ["."]
+  pruneopts = ""
+  revision = "98ec13f34aabf44cc914c65a1cfb7b9bc815aef1"
+  version = "v0.1.4"
+
+[[projects]]
+  digest = "1:5794dadc5456af270fc564d98efbfa1f3627cd6c733ca772d14409793772064f"
+  name = "github.com/mattn/go-isatty"
+  packages = ["."]
+  pruneopts = ""
+  revision = "88ba11cfdc67c7588b30042edf244b2875f892b6"
+  version = "v0.0.10"
+
+[[projects]]
+  digest = "1:63722a4b1e1717be7b98fc686e0b30d5e7f734b9e93d7dee86293b6deab7ea28"
+  name = "github.com/matttproud/golang_protobuf_extensions"
+  packages = ["pbutil"]
+  pruneopts = ""
+  revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
+  version = "v1.0.1"
+
+[[projects]]
+  digest = "1:713b341855f1480e4baca1e7c5434e1d266441340685ecbde32d59bdc065fb3f"
+  name = "github.com/mitchellh/go-wordwrap"
+  packages = ["."]
+  pruneopts = ""
+  revision = "9e67c67572bc5dd02aef930e2b0ae3c02a4b5a5c"
+  version = "v1.0.0"
+
+[[projects]]
+  digest = "1:0c0ff2a89c1bb0d01887e1dac043ad7efbf3ec77482ef058ac423d13497e16fd"
+  name = "github.com/modern-go/concurrent"
+  packages = ["."]
+  pruneopts = ""
+  revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
+  version = "1.0.3"
+
+[[projects]]
+  digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
+  name = "github.com/modern-go/reflect2"
+  packages = ["."]
+  pruneopts = ""
+  revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
+  version = "1.0.1"
+
+[[projects]]
+  digest = "1:5d9b668b0b4581a978f07e7d2e3314af18eb27b3fb5d19b70185b7c575723d11"
+  name = "github.com/opencontainers/go-digest"
+  packages = ["."]
+  pruneopts = ""
+  revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
+  version = "v1.0.0-rc1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:5f0faa008e8ff4221b55a1a5057c8b02cb2fd68da6a65c9e31c82b72cbc836d0"
+  name = "github.com/petar/GoLLRB"
+  packages = ["llrb"]
+  pruneopts = ""
+  revision = "33fb24c13b99c46c93183c291836c573ac382536"
+
+[[projects]]
+  digest = "1:4709c61d984ef9ba99b037b047546d8a576ae984fb49486e48d99658aa750cd5"
+  name = "github.com/peterbourgon/diskv"
+  packages = ["."]
+  pruneopts = ""
+  revision = "0be1b92a6df0e4f5cb0a5d15fb7f643d0ad93ce6"
+  version = "v3.0.0"
+
+[[projects]]
+  digest = "1:1d7e1867c49a6dd9856598ef7c3123604ea3daabf5b83f303ff457bcbc410b1d"
+  name = "github.com/pkg/errors"
+  packages = ["."]
+  pruneopts = ""
+  revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
+  version = "v0.8.1"
+
+[[projects]]
+  digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411"
+  name = "github.com/pmezard/go-difflib"
+  packages = ["difflib"]
+  pruneopts = ""
+  revision = "792786c7400a136282c1664665ae0a8db921c6c2"
+  version = "v1.0.0"
+
+[[projects]]
+  digest = "1:6f218995d6a74636cfcab45ce03005371e682b4b9bee0e5eb0ccfd83ef85364f"
+  name = "github.com/prometheus/client_golang"
+  packages = [
+    "api",
+    "api/prometheus/v1",
+    "prometheus",
+    "prometheus/internal",
+    "prometheus/promhttp",
+  ]
+  pruneopts = ""
+  revision = "505eaef017263e299324067d40ca2c48f6a2cf50"
+  version = "v0.9.2"
+
+[[projects]]
+  branch = "master"
+  digest = "1:cd67319ee7536399990c4b00fae07c3413035a53193c644549a676091507cadc"
+  name = "github.com/prometheus/client_model"
+  packages = ["go"]
+  pruneopts = ""
+  revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
+
+[[projects]]
+  digest = "1:96af18a3819d2ff7d6aa07e6e50955b11e477dbc8b890324c67462b84adca56b"
+  name = "github.com/prometheus/common"
+  packages = [
+    "expfmt",
+    "internal/bitbucket.org/ww/goautoneg",
+    "log",
+    "model",
+  ]
+  pruneopts = ""
+  revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
+  version = "v0.2.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:5dff64a37ab1e65130c24f01d5fbda61226b73cc61b6f0c8af24373509a89b73"
+  name = "github.com/prometheus/procfs"
+  packages = [
+    ".",
+    "internal/util",
+    "iostats",
+    "nfs",
+    "xfs",
+  ]
+  pruneopts = ""
+  revision = "55ae3d9d557340b5bc24cd8aa5f6fa2c2ab31352"
+
+[[projects]]
+  digest = "1:2761e287c811d0948d47d0252b82281eca3801eb3c9d5f9530956643d5b9f430"
+  name = "github.com/russross/blackfriday"
+  packages = ["."]
+  pruneopts = ""
+  revision = "05f3235734ad95d0016f6a23902f06461fcf567a"
+  version = "v1.5.2"
+
+[[projects]]
+  digest = "1:9a3c631555e0351fdc4e696577bb63afd90c399d782a8462dba9d100d7021db3"
+  name = "github.com/sirupsen/logrus"
+  packages = ["."]
+  pruneopts = ""
+  revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5"
+  version = "v1.3.0"
+
+[[projects]]
+  digest = "1:9a1b782e10224f243d627f9dacfd43e69752247f6edf6bfa83c9c773cfd3ff11"
+  name = "github.com/spaceapegames/go-wavefront"
+  packages = ["."]
+  pruneopts = ""
+  revision = "d617b8803739eb11a2e4db6097b51a64a6def5db"
+  version = "v1.6.2"
+
+[[projects]]
+  digest = "1:0c63b3c7ad6d825a898f28cb854252a3b29d37700c68a117a977263f5ec94efe"
+  name = "github.com/spf13/cobra"
+  packages = ["."]
+  pruneopts = ""
+  revision = "f2b07da1e2c38d5f12845a4f607e2e1018cbb1f5"
+  version = "v0.0.5"
+
+[[projects]]
+  digest = "1:cbaf13cdbfef0e4734ed8a7504f57fe893d471d62a35b982bf6fb3f036449a66"
+  name = "github.com/spf13/pflag"
+  packages = ["."]
+  pruneopts = ""
+  revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
+  version = "v1.0.3"
+
+[[projects]]
+  digest = "1:711eebe744c0151a9d09af2315f0bb729b2ec7637ef4c410fa90a18ef74b65b6"
+  name = "github.com/stretchr/objx"
+  packages = ["."]
+  pruneopts = ""
+  revision = "477a77ecc69700c7cdeb1fa9e129548e1c1c393c"
+  version = "v0.1.1"
+
+[[projects]]
+  digest = "1:c587772fb8ad29ad4db67575dad25ba17a51f072ff18a22b4f0257a4d9c24f75"
+  name = "github.com/stretchr/testify"
+  packages = [
+    "assert",
+    "mock",
+  ]
+  pruneopts = ""
+  revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
+  version = "v1.2.2"
+
+[[projects]]
+  digest = "1:857a9ecd5cb13379ecc8f798f6e6b6b574c98b9355657d91e068275f1120aaf7"
+  name = "github.com/valyala/bytebufferpool"
+  packages = ["."]
+  pruneopts = ""
+  revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7"
+  version = "v1.0.0"
+
+[[projects]]
+  digest = "1:1ad3ae8a5edf223abb8435e16ccc0696ce886c6f889e100809122e931e7423b2"
+  name = "github.com/valyala/fasttemplate"
+  packages = ["."]
+  pruneopts = ""
+  revision = "8b5e4e491ab636663841c42ea3c5a9adebabaf36"
+  version = "v1.0.1"
+
+[[projects]]
+  digest = "1:603b1ea14337a8198a2de0716d1c707e8995e3dea42c0dc17364a93bc504fb87"
+  name = "github.com/vektra/mockery"
+  packages = ["."]
+  pruneopts = ""
+  revision = "e78b021dcbb558a8e7ac1fc5bc757ad7c277bb81"
+
+[[projects]]
+  branch = "master"
+  digest = "1:f7be435e0ca22e2cd62b2d2542081a231685837170a87a3662abb7cdf9f3f1cd"
+  name = "golang.org/x/crypto"
+  packages = [
+    "ed25519",
+    "ed25519/internal/edwards25519",
+    "pbkdf2",
+    "ssh/terminal",
+  ]
+  pruneopts = ""
+  revision = "3d3f9f413869b949e48070b5bc593aa22cc2b8f2"
+
+[[projects]]
+  branch = "master"
+  digest = "1:4ac199b027ed34460ec4e0a92c882156f561e78cd046fef095e50f867462435a"
+  name = "golang.org/x/net"
+  packages = [
+    "context",
+    "context/ctxhttp",
+    "http/httpguts",
+    "http2",
+    "http2/hpack",
+    "idna",
+  ]
+  pruneopts = ""
+  revision = "adae6a3d119ae4890b46832a2e88a95adc62b8e7"
+
+[[projects]]
+  branch = "master"
+  digest = "1:51d339a1d79f5c617fba14414aefb7dfd184b8ba0ddbb9f95251430b67c8aab8"
+  name = "golang.org/x/oauth2"
+  packages = [
+    ".",
+    "google",
+    "internal",
+    "jws",
+    "jwt",
+  ]
+  pruneopts = ""
+  revision = "f42d05182288abf10faef86d16c0d07b8d40ea2d"
+
+[[projects]]
+  branch = "master"
+  digest = "1:bae7ec6144727bacb0f06565215267a39134f63a4955114d03961ca9061a1e97"
+  name = "golang.org/x/sys"
+  packages = [
+    "unix",
+    "windows",
+    "windows/registry",
+    "windows/svc/eventlog",
+  ]
+  pruneopts = ""
+  revision = "93218def8b18e66adbdab3eca8ec334700329f1f"
+
+[[projects]]
+  digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
+  name = "golang.org/x/text"
+  packages = [
+    "collate",
+    "collate/build",
+    "encoding",
+    "encoding/internal",
+    "encoding/internal/identifier",
+    "encoding/unicode",
+    "internal/colltab",
+    "internal/gen",
+    "internal/tag",
+    "internal/triegen",
+    "internal/ucd",
+    "internal/utf8internal",
+    "language",
+    "runes",
+    "secure/bidirule",
+    "transform",
+    "unicode/bidi",
+    "unicode/cldr",
+    "unicode/norm",
+    "unicode/rangetable",
+    "width",
+  ]
+  pruneopts = ""
+  revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
+  version = "v0.3.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:14cb1d4240bcbbf1386ae763957e04e2765ec4e4ce7bb2769d05fa6faccd774e"
+  name = "golang.org/x/time"
+  packages = ["rate"]
+  pruneopts = ""
+  revision = "85acf8d2951cb2a3bde7632f9ff273ef0379bcbd"
+
+[[projects]]
+  branch = "master"
+  digest = "1:882f3bb4a5ee4ce6f76c9c5833dd5ccb3282269949cd9f1c0d9212b45cb298c9"
+  name = "golang.org/x/tools"
+  packages = [
+    "go/ast/astutil",
+    "imports",
+    "internal/fastwalk",
+    "internal/gopathwalk",
+  ]
+  pruneopts = ""
+  revision = "2ddaf7f79a0937ffa9072ede7b696fd084abfe86"
+
+[[projects]]
+  digest = "1:77d3cff3a451d50be4b52db9c7766c0d8570ba47593f0c9dc72173adb208e788"
+  name = "google.golang.org/appengine"
+  packages = [
+    ".",
+    "internal",
+    "internal/app_identity",
+    "internal/base",
+    "internal/datastore",
+    "internal/log",
+    "internal/modules",
+    "internal/remote_api",
+    "internal/urlfetch",
+    "urlfetch",
+  ]
+  pruneopts = ""
+  revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
+  version = "v1.3.0"
+
+[[projects]]
+  digest = "1:15d017551627c8bb091bde628215b2861bed128855343fdd570c62d08871f6e1"
+  name = "gopkg.in/alecthomas/kingpin.v2"
+  packages = ["."]
+  pruneopts = ""
+  revision = "947dcec5ba9c011838740e680966fd7087a71d0d"
+  version = "v2.2.6"
+
+[[projects]]
+  digest = "1:75fb3fcfc73a8c723efde7777b40e8e8ff9babf30d8c56160d01beffea8a95a6"
+  name = "gopkg.in/inf.v0"
+  packages = ["."]
+  pruneopts = ""
+  revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
+  version = "v0.9.1"
+
+[[projects]]
+  digest = "1:ddc5fa8f9159bea7d1ce58143e6d8fd8054018f7bc3709940aa7f7bc92855ed9"
+  name = "gopkg.in/square/go-jose.v2"
+  packages = [
+    ".",
+    "cipher",
+    "json",
+    "jwt",
+  ]
+  pruneopts = ""
+  revision = "ef984e69dd356202fd4e4910d4d9c24468bdf0b8"
+  version = "v2.1.9"
+
+[[projects]]
+  digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
+  name = "gopkg.in/yaml.v2"
+  packages = ["."]
+  pruneopts = ""
+  revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
+  version = "v2.2.1"
+
+[[projects]]
+  branch = "release-1.16"
+  digest = "1:5e5cfbab57ea5444c1eb295a39fdc403f097f5ace592c829db7b3e0e3ea66903"
+  name = "k8s.io/api"
+  packages = [
+    "admission/v1",
+    "admission/v1beta1",
+    "admissionregistration/v1",
+    "admissionregistration/v1beta1",
+    "apps/v1",
+    "apps/v1beta1",
+    "apps/v1beta2",
+    "auditregistration/v1alpha1",
+    "authentication/v1",
+    "authentication/v1beta1",
+    "authorization/v1",
+    "authorization/v1beta1",
+    "autoscaling/v1",
+    "autoscaling/v2beta1",
+    "autoscaling/v2beta2",
+    "batch/v1",
+    "batch/v1beta1",
+    "batch/v2alpha1",
+    "certificates/v1beta1",
+    "coordination/v1",
+    "coordination/v1beta1",
+    "core/v1",
+    "discovery/v1alpha1",
+    "events/v1beta1",
+    "extensions/v1beta1",
+    "imagepolicy/v1alpha1",
+    "networking/v1",
+    "networking/v1beta1",
+    "node/v1alpha1",
+    "node/v1beta1",
+    "policy/v1beta1",
+    "rbac/v1",
+    "rbac/v1alpha1",
+    "rbac/v1beta1",
+    "scheduling/v1",
+    "scheduling/v1alpha1",
+    "scheduling/v1beta1",
+    "settings/v1alpha1",
+    "storage/v1",
+    "storage/v1alpha1",
+    "storage/v1beta1",
+  ]
+  pruneopts = ""
+  revision = "195af9ec35214c6d98662c5791364285bf2e2cf2"
+
+[[projects]]
+  branch = "release-1.16"
+  digest = "1:ea9d3d1bec3c3ecdfef0e0f92dc1c99468e9a13fedfb7f1bc297ae6c88968619"
+  name = "k8s.io/apiextensions-apiserver"
+  packages = [
+    "pkg/apis/apiextensions",
+    "pkg/apis/apiextensions/v1beta1",
+    "pkg/features",
+  ]
+  pruneopts = ""
+  revision = "59c675dd9926a891c040ac814ecea8dba8598c63"
+
+[[projects]]
+  branch = "release-1.16"
+  digest = "1:8ac118b8194fbc5d845ca59c3e3ca2e179ffe49a3f4db9093cd636f423f32f2d"
+  name = "k8s.io/apimachinery"
+  packages = [
+    "pkg/api/equality",
+    "pkg/api/errors",
+    "pkg/api/meta",
+    "pkg/api/meta/testrestmapper",
+    "pkg/api/resource",
+    "pkg/api/validation",
+    "pkg/apis/meta/internalversion",
+    "pkg/apis/meta/v1",
+    "pkg/apis/meta/v1/unstructured",
+    "pkg/apis/meta/v1/unstructured/unstructuredscheme",
+    "pkg/apis/meta/v1/validation",
+    "pkg/apis/meta/v1beta1",
+    "pkg/conversion",
+    "pkg/conversion/queryparams",
+    "pkg/fields",
+    "pkg/labels",
+    "pkg/runtime",
+    "pkg/runtime/schema",
+    "pkg/runtime/serializer",
+    "pkg/runtime/serializer/json",
+    "pkg/runtime/serializer/protobuf",
+    "pkg/runtime/serializer/recognizer",
+    "pkg/runtime/serializer/streaming",
+    "pkg/runtime/serializer/versioning",
+    "pkg/selection",
+    "pkg/types",
+    "pkg/util/cache",
+    "pkg/util/clock",
+    "pkg/util/diff",
+    "pkg/util/duration",
+    "pkg/util/errors",
+    "pkg/util/framer",
+    "pkg/util/httpstream",
+    "pkg/util/httpstream/spdy",
+    "pkg/util/intstr",
+    "pkg/util/json",
+    "pkg/util/mergepatch",
+    "pkg/util/naming",
+    "pkg/util/net",
+    "pkg/util/rand",
+    "pkg/util/remotecommand",
+    "pkg/util/runtime",
+    "pkg/util/sets",
+    "pkg/util/strategicpatch",
+    "pkg/util/uuid",
+    "pkg/util/validation",
+    "pkg/util/validation/field",
+    "pkg/util/version",
+    "pkg/util/wait",
+    "pkg/util/yaml",
+    "pkg/version",
+    "pkg/watch",
+    "third_party/forked/golang/json",
+    "third_party/forked/golang/netutil",
+    "third_party/forked/golang/reflect",
+  ]
+  pruneopts = ""
+  revision = "a2eda9f80ab8a454a81bdde16d62a1afe5f931c0"
+
+[[projects]]
+  branch = "release-1.16"
+  digest = "1:e077a9d0f91972dd98d17b570a7d2f9dc45bf1104a9fd836ca727f193e4c617c"
+  name = "k8s.io/apiserver"
+  packages = [
+    "pkg/authentication/authenticator",
+    "pkg/authentication/serviceaccount",
+    "pkg/authentication/user",
+    "pkg/features",
+    "pkg/storage/names",
+    "pkg/util/feature",
+  ]
+  pruneopts = ""
+  revision = "3fdfe2c6555525ae54a58d22cd7f014a25ce749d"
+
+[[projects]]
+  branch = "release-1.16"
+  digest = "1:b46a88b317c3187b6fa7c5351eca48b35aad182eee371168677747430ff955bb"
+  name = "k8s.io/cli-runtime"
+  packages = [
+    "pkg/genericclioptions",
+    "pkg/kustomize",
+    "pkg/kustomize/k8sdeps",
+    "pkg/kustomize/k8sdeps/configmapandsecret",
+    "pkg/kustomize/k8sdeps/kunstruct",
+    "pkg/kustomize/k8sdeps/kv",
+    "pkg/kustomize/k8sdeps/transformer",
+    "pkg/kustomize/k8sdeps/transformer/hash",
+    "pkg/kustomize/k8sdeps/transformer/patch",
+    "pkg/kustomize/k8sdeps/validator",
+    "pkg/printers",
+    "pkg/resource",
+  ]
+  pruneopts = ""
+  revision = "6bff60de437070d7e8644b7a930837d5de512240"
+
+[[projects]]
+  branch = "release-13.0"
+  digest = "1:9e7a28fb6a57b9eb2e7730a2d152a5618a0e913415a13bca76607e799d39fd85"
+  name = "k8s.io/client-go"
+  packages = [
+    "discovery",
+    "discovery/cached/disk",
+    "discovery/fake",
+    "dynamic",
+    "dynamic/dynamicinformer",
+    "dynamic/dynamiclister",
+    "dynamic/fake",
+    "informers",
+    "informers/admissionregistration",
+    "informers/admissionregistration/v1",
+    "informers/admissionregistration/v1beta1",
+    "informers/apps",
+    "informers/apps/v1",
+    "informers/apps/v1beta1",
+    "informers/apps/v1beta2",
+    "informers/auditregistration",
+    "informers/auditregistration/v1alpha1",
+    "informers/autoscaling",
+    "informers/autoscaling/v1",
+    "informers/autoscaling/v2beta1",
+    "informers/autoscaling/v2beta2",
+    "informers/batch",
+    "informers/batch/v1",
+    "informers/batch/v1beta1",
+    "informers/batch/v2alpha1",
+    "informers/certificates",
+    "informers/certificates/v1beta1",
+    "informers/coordination",
+    "informers/coordination/v1",
+    "informers/coordination/v1beta1",
+    "informers/core",
+    "informers/core/v1",
+    "informers/discovery",
+    "informers/discovery/v1alpha1",
+    "informers/events",
+    "informers/events/v1beta1",
+    "informers/extensions",
+    "informers/extensions/v1beta1",
+    "informers/internalinterfaces",
+    "informers/networking",
+    "informers/networking/v1",
+    "informers/networking/v1beta1",
+    "informers/node",
+    "informers/node/v1alpha1",
+    "informers/node/v1beta1",
+    "informers/policy",
+    "informers/policy/v1beta1",
+    "informers/rbac",
+    "informers/rbac/v1",
+    "informers/rbac/v1alpha1",
+    "informers/rbac/v1beta1",
+    "informers/scheduling",
+    "informers/scheduling/v1",
+    "informers/scheduling/v1alpha1",
+    "informers/scheduling/v1beta1",
+    "informers/settings",
+    "informers/settings/v1alpha1",
+    "informers/storage",
+    "informers/storage/v1",
+    "informers/storage/v1alpha1",
+    "informers/storage/v1beta1",
+    "kubernetes",
+    "kubernetes/fake",
+    "kubernetes/scheme",
+    "kubernetes/typed/admissionregistration/v1",
+    "kubernetes/typed/admissionregistration/v1/fake",
+    "kubernetes/typed/admissionregistration/v1beta1",
+    "kubernetes/typed/admissionregistration/v1beta1/fake",
+    "kubernetes/typed/apps/v1",
+    "kubernetes/typed/apps/v1/fake",
+    "kubernetes/typed/apps/v1beta1",
+    "kubernetes/typed/apps/v1beta1/fake",
+    "kubernetes/typed/apps/v1beta2",
+    "kubernetes/typed/apps/v1beta2/fake",
+    "kubernetes/typed/auditregistration/v1alpha1",
+    "kubernetes/typed/auditregistration/v1alpha1/fake",
+    "kubernetes/typed/authentication/v1",
+    "kubernetes/typed/authentication/v1/fake",
+    "kubernetes/typed/authentication/v1beta1",
+    "kubernetes/typed/authentication/v1beta1/fake",
+    "kubernetes/typed/authorization/v1",
+    "kubernetes/typed/authorization/v1/fake",
+    "kubernetes/typed/authorization/v1beta1",
+    "kubernetes/typed/authorization/v1beta1/fake",
+    "kubernetes/typed/autoscaling/v1",
+    "kubernetes/typed/autoscaling/v1/fake",
+    "kubernetes/typed/autoscaling/v2beta1",
+    "kubernetes/typed/autoscaling/v2beta1/fake",
+    "kubernetes/typed/autoscaling/v2beta2",
+    "kubernetes/typed/autoscaling/v2beta2/fake",
+    "kubernetes/typed/batch/v1",
+    "kubernetes/typed/batch/v1/fake",
+    "kubernetes/typed/batch/v1beta1",
+    "kubernetes/typed/batch/v1beta1/fake",
+    "kubernetes/typed/batch/v2alpha1",
+    "kubernetes/typed/batch/v2alpha1/fake",
+    "kubernetes/typed/certificates/v1beta1",
+    "kubernetes/typed/certificates/v1beta1/fake",
+    "kubernetes/typed/coordination/v1",
+    "kubernetes/typed/coordination/v1/fake",
+    "kubernetes/typed/coordination/v1beta1",
+    "kubernetes/typed/coordination/v1beta1/fake",
+    "kubernetes/typed/core/v1",
+    "kubernetes/typed/core/v1/fake",
+    "kubernetes/typed/discovery/v1alpha1",
+    "kubernetes/typed/discovery/v1alpha1/fake",
+    "kubernetes/typed/events/v1beta1",
+    "kubernetes/typed/events/v1beta1/fake",
+    "kubernetes/typed/extensions/v1beta1",
+    "kubernetes/typed/extensions/v1beta1/fake",
+    "kubernetes/typed/networking/v1",
+    "kubernetes/typed/networking/v1/fake",
+    "kubernetes/typed/networking/v1beta1",
+    "kubernetes/typed/networking/v1beta1/fake",
+    "kubernetes/typed/node/v1alpha1",
+    "kubernetes/typed/node/v1alpha1/fake",
+    "kubernetes/typed/node/v1beta1",
+    "kubernetes/typed/node/v1beta1/fake",
+    "kubernetes/typed/policy/v1beta1",
+    "kubernetes/typed/policy/v1beta1/fake",
+    "kubernetes/typed/rbac/v1",
+    "kubernetes/typed/rbac/v1/fake",
+    "kubernetes/typed/rbac/v1alpha1",
+    "kubernetes/typed/rbac/v1alpha1/fake",
+    "kubernetes/typed/rbac/v1beta1",
+    "kubernetes/typed/rbac/v1beta1/fake",
+    "kubernetes/typed/scheduling/v1",
+    "kubernetes/typed/scheduling/v1/fake",
+    "kubernetes/typed/scheduling/v1alpha1",
+    "kubernetes/typed/scheduling/v1alpha1/fake",
+    "kubernetes/typed/scheduling/v1beta1",
+    "kubernetes/typed/scheduling/v1beta1/fake",
+    "kubernetes/typed/settings/v1alpha1",
+    "kubernetes/typed/settings/v1alpha1/fake",
+    "kubernetes/typed/storage/v1",
+    "kubernetes/typed/storage/v1/fake",
+    "kubernetes/typed/storage/v1alpha1",
+    "kubernetes/typed/storage/v1alpha1/fake",
+    "kubernetes/typed/storage/v1beta1",
+    "kubernetes/typed/storage/v1beta1/fake",
+    "listers/admissionregistration/v1",
+    "listers/admissionregistration/v1beta1",
+    "listers/apps/v1",
+    "listers/apps/v1beta1",
+    "listers/apps/v1beta2",
+    "listers/auditregistration/v1alpha1",
+    "listers/autoscaling/v1",
+    "listers/autoscaling/v2beta1",
+    "listers/autoscaling/v2beta2",
+    "listers/batch/v1",
+    "listers/batch/v1beta1",
+    "listers/batch/v2alpha1",
+    "listers/certificates/v1beta1",
+    "listers/coordination/v1",
+    "listers/coordination/v1beta1",
+    "listers/core/v1",
+    "listers/discovery/v1alpha1",
+    "listers/events/v1beta1",
+    "listers/extensions/v1beta1",
+    "listers/networking/v1",
+    "listers/networking/v1beta1",
+    "listers/node/v1alpha1",
+    "listers/node/v1beta1",
+    "listers/policy/v1beta1",
+    "listers/rbac/v1",
+    "listers/rbac/v1alpha1",
+    "listers/rbac/v1beta1",
+    "listers/scheduling/v1",
+    "listers/scheduling/v1alpha1",
+    "listers/scheduling/v1beta1",
+    "listers/settings/v1alpha1",
+    "listers/storage/v1",
+    "listers/storage/v1alpha1",
+    "listers/storage/v1beta1",
+    "metadata",
+    "metadata/metadatainformer",
+    "metadata/metadatalister",
+    "pkg/apis/clientauthentication",
+    "pkg/apis/clientauthentication/v1alpha1",
+    "pkg/apis/clientauthentication/v1beta1",
+    "pkg/version",
+    "plugin/pkg/client/auth/exec",
+    "plugin/pkg/client/auth/gcp",
+    "plugin/pkg/client/auth/oidc",
+    "rest",
+    "rest/fake",
+    "rest/watch",
+    "restmapper",
+    "scale",
+    "scale/scheme",
+    "scale/scheme/appsint",
+    "scale/scheme/appsv1beta1",
+    "scale/scheme/appsv1beta2",
+    "scale/scheme/autoscalingv1",
+    "scale/scheme/extensionsint",
+    "scale/scheme/extensionsv1beta1",
+    "testing",
+    "third_party/forked/golang/template",
+    "tools/auth",
+    "tools/cache",
+    "tools/clientcmd",
+    "tools/clientcmd/api",
+    "tools/clientcmd/api/latest",
+    "tools/clientcmd/api/v1",
+    "tools/metrics",
+    "tools/pager",
+    "tools/record",
+    "tools/record/util",
+    "tools/reference",
+    "tools/remotecommand",
+    "tools/watch",
+    "transport",
+    "transport/spdy",
+    "util/cert",
+    "util/connrotation",
+    "util/exec",
+    "util/flowcontrol",
+    "util/homedir",
+    "util/jsonpath",
+    "util/keyutil",
+    "util/retry",
+    "util/workqueue",
+  ]
+  pruneopts = ""
+  revision = "f06fe3961ca9f09ba2f23c3c83decd95186d71c2"
+
+[[projects]]
+  branch = "master"
+  digest = "1:2929909e6a506832aa3924522331d43aab91d17c85399802bd960e428cef5d6d"
+  name = "k8s.io/cluster-bootstrap"
+  packages = [
+    "token/api",
+    "token/util",
+    "util/secrets",
+  ]
+  pruneopts = ""
+  revision = "f632ced2d31d86dd39523c0625e3b52642d5289f"
+
+[[projects]]
+  branch = "release-1.16"
+  digest = "1:254da4cb69b3776686b730a206e081e6f8898bb64760619d1895c25c407e718f"
+  name = "k8s.io/code-generator"
+  packages = [
+    "cmd/client-gen",
+    "cmd/client-gen/args",
+    "cmd/client-gen/generators",
+    "cmd/client-gen/generators/fake",
+    "cmd/client-gen/generators/scheme",
+    "cmd/client-gen/generators/util",
+    "cmd/client-gen/path",
+    "cmd/client-gen/types",
+    "pkg/namer",
+    "pkg/util",
+  ]
+  pruneopts = ""
+  revision = "8e001e5d18949be7e823ccb9cfe9b60026e7bda0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:727faf154ba5437cba7957d087b3e9f330f6ee0e15f91e2eba4dbba491bb53ff"
+  name = "k8s.io/component-base"
+  packages = [
+    "config",
+    "featuregate",
+  ]
+  pruneopts = ""
+  revision = "4062e14deebed23a9af22e52b675e89cb753b99e"
+
+[[projects]]
+  branch = "master"
+  digest = "1:0cc7d194e005097afad585545a3049ac7b5d1e3a1bfa86aa6bf6f2fb0e0a5063"
+  name = "k8s.io/gengo"
+  packages = [
+    "args",
+    "examples/set-gen/sets",
+    "generator",
+    "namer",
+    "parser",
+    "types",
+  ]
+  pruneopts = ""
+  revision = "fd15ee9cc2f77baa4f31e59e6acbf21146455073"
+
+[[projects]]
+  digest = "1:32e54cfe25c8eea758b1e0d3aec033ba652d0557cb79ee62d1ba239f5f694c0e"
+  name = "k8s.io/klog"
+  packages = ["."]
+  pruneopts = ""
+  revision = "89e63fd5117f8c20208186ef85f096703a280c20"
+  version = "v0.3.1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:e5d4ca90c0f3862515c98454bb37d4d340f4ceeca60ac3e0a5cb5857360aed7c"
+  name = "k8s.io/kube-openapi"
+  packages = [
+    "cmd/openapi-gen",
+    "cmd/openapi-gen/args",
+    "pkg/common",
+    "pkg/generators",
+    "pkg/generators/rules",
+    "pkg/util/proto",
+    "pkg/util/proto/testing",
+    "pkg/util/proto/validation",
+    "pkg/util/sets",
+  ]
+  pruneopts = ""
+  revision = "0317810137be915b9cf888946c6e115c1bfac693"
+
+[[projects]]
+  branch = "release-1.16"
+  digest = "1:687af22932f9b53ff2e6755b2eefe160f076d522794abb980f0ddb187bcefacd"
+  name = "k8s.io/kubectl"
+  packages = [
+    "pkg/cmd/testing",
+    "pkg/cmd/util",
+    "pkg/scheme",
+    "pkg/util/interrupt",
+    "pkg/util/openapi",
+    "pkg/util/openapi/testing",
+    "pkg/util/openapi/validation",
+    "pkg/util/templates",
+    "pkg/util/term",
+    "pkg/validation",
+    "pkg/version",
+  ]
+  pruneopts = ""
+  revision = "14647fd13a8b4cffc5a8f327b0018e037f72e4e8"
+
+[[projects]]
+  branch = "release-1.16"
+  digest = "1:985440fa37318b73e722b1d50d75635e08e2ed76aac87e7362fadcad4a9d8fa3"
+  name = "k8s.io/kubernetes"
+  packages = [
+    "cmd/kubeadm/app/apis/kubeadm",
+    "cmd/kubeadm/app/constants",
+    "cmd/kubeadm/app/util",
+    "cmd/kubeadm/app/version",
+    "pkg/api/legacyscheme",
+    "pkg/api/service",
+    "pkg/api/v1/pod",
+    "pkg/apis/apps",
+    "pkg/apis/autoscaling",
+    "pkg/apis/core",
+    "pkg/apis/core/helper",
+    "pkg/apis/core/install",
+    "pkg/apis/core/pods",
+    "pkg/apis/core/v1",
+    "pkg/apis/core/v1/helper",
+    "pkg/apis/core/validation",
+    "pkg/apis/scheduling",
+    "pkg/capabilities",
+    "pkg/controller",
+    "pkg/features",
+    "pkg/fieldpath",
+    "pkg/kubelet/apis/config",
+    "pkg/kubelet/types",
+    "pkg/master/ports",
+    "pkg/proxy/apis/config",
+    "pkg/registry/core/service/allocator",
+    "pkg/registry/core/service/ipallocator",
+    "pkg/security/apparmor",
+    "pkg/serviceaccount",
+    "pkg/util/hash",
+    "pkg/util/labels",
+    "pkg/util/node",
+    "pkg/util/parsers",
+    "pkg/util/taints",
+    "pkg/util/workqueue/prometheus",
+  ]
+  pruneopts = ""
+  revision = "a2ff5d71deafff1d9688eb6f7533dd239980c420"
+
+[[projects]]
+  branch = "master"
+  digest = "1:874afa816ece04beefd8724c8d397fdccc80c5d6d72ed8567e9af47b928887c9"
+  name = "k8s.io/utils"
+  packages = [
+    "buffer",
+    "exec",
+    "integer",
+    "net",
+    "path",
+    "pointer",
+    "trace",
+  ]
+  pruneopts = ""
+  revision = "69764acb6e8e900b7c05296c5d3c9c19545475f9"
+
+[[projects]]
+  digest = "1:0b2daace3dcced8712072529b621360cf520f3c2ead92d755f35a0ec8dca2714"
+  name = "sigs.k8s.io/kustomize"
+  packages = [
+    "pkg/commands/build",
+    "pkg/constants",
+    "pkg/expansion",
+    "pkg/factory",
+    "pkg/fs",
+    "pkg/git",
+    "pkg/gvk",
+    "pkg/ifc",
+    "pkg/ifc/transformer",
+    "pkg/image",
+    "pkg/internal/error",
+    "pkg/loader",
+    "pkg/patch",
+    "pkg/patch/transformer",
+    "pkg/resid",
+    "pkg/resmap",
+    "pkg/resource",
+    "pkg/target",
+    "pkg/transformers",
+    "pkg/transformers/config",
+    "pkg/transformers/config/defaultconfig",
+    "pkg/types",
+  ]
+  pruneopts = ""
+  revision = "a6f65144121d1955266b0cd836ce954c04122dc8"
+  version = "v2.0.3"
+
+[[projects]]
+  digest = "1:321081b4a44256715f2b68411d8eda9a17f17ebfe6f0cc61d2cc52d11c08acfa"
+  name = "sigs.k8s.io/yaml"
+  packages = ["."]
+  pruneopts = ""
+  revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
+  version = "v1.1.0"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  input-imports = [
+    "github.com/antonmedv/expr",
+    "github.com/bouk/monkey",
+    "github.com/emicklei/go-restful",
+    "github.com/ghodss/yaml",
+    "github.com/go-openapi/spec",
+    "github.com/juju/ansiterm",
+    "github.com/pkg/errors",
+    "github.com/prometheus/client_golang/api",
+    "github.com/prometheus/client_golang/api/prometheus/v1",
+    "github.com/prometheus/client_golang/prometheus",
+    "github.com/prometheus/client_golang/prometheus/promhttp",
+    "github.com/prometheus/common/log",
+    "github.com/prometheus/common/model",
+    "github.com/sirupsen/logrus",
+    "github.com/spaceapegames/go-wavefront",
+    "github.com/spf13/cobra",
+    "github.com/stretchr/testify/assert",
+    "github.com/stretchr/testify/mock",
+    "github.com/valyala/fasttemplate",
+    "github.com/vektra/mockery",
+    "k8s.io/api/apps/v1",
+    "k8s.io/api/batch/v1",
+    "k8s.io/api/core/v1",
+    "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1",
+    "k8s.io/apimachinery/pkg/api/equality",
+    "k8s.io/apimachinery/pkg/api/errors",
+    "k8s.io/apimachinery/pkg/api/meta",
+    "k8s.io/apimachinery/pkg/apis/meta/v1",
+    "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
+    "k8s.io/apimachinery/pkg/fields",
+    "k8s.io/apimachinery/pkg/labels",
+    "k8s.io/apimachinery/pkg/runtime",
+    "k8s.io/apimachinery/pkg/runtime/schema",
+    "k8s.io/apimachinery/pkg/runtime/serializer",
+    "k8s.io/apimachinery/pkg/selection",
+    "k8s.io/apimachinery/pkg/types",
+    "k8s.io/apimachinery/pkg/util/duration",
+    "k8s.io/apimachinery/pkg/util/intstr",
+    "k8s.io/apimachinery/pkg/util/rand",
+    "k8s.io/apimachinery/pkg/util/runtime",
+    "k8s.io/apimachinery/pkg/util/strategicpatch",
+    "k8s.io/apimachinery/pkg/util/uuid",
+    "k8s.io/apimachinery/pkg/util/validation",
+    "k8s.io/apimachinery/pkg/util/wait",
+    "k8s.io/apimachinery/pkg/watch",
+    "k8s.io/apiserver/pkg/storage/names",
+    "k8s.io/cli-runtime/pkg/genericclioptions",
+    "k8s.io/client-go/discovery",
+    "k8s.io/client-go/discovery/fake",
+    "k8s.io/client-go/dynamic",
+    "k8s.io/client-go/dynamic/dynamicinformer",
+    "k8s.io/client-go/dynamic/fake",
+    "k8s.io/client-go/informers",
+    "k8s.io/client-go/informers/apps/v1",
+    "k8s.io/client-go/informers/batch/v1",
+    "k8s.io/client-go/informers/core/v1",
+    "k8s.io/client-go/kubernetes",
+    "k8s.io/client-go/kubernetes/fake",
+    "k8s.io/client-go/kubernetes/scheme",
+    "k8s.io/client-go/kubernetes/typed/core/v1",
+    "k8s.io/client-go/listers/apps/v1",
+    "k8s.io/client-go/listers/batch/v1",
+    "k8s.io/client-go/listers/core/v1",
+    "k8s.io/client-go/plugin/pkg/client/auth/gcp",
+    "k8s.io/client-go/plugin/pkg/client/auth/oidc",
+    "k8s.io/client-go/rest",
+    "k8s.io/client-go/testing",
+    "k8s.io/client-go/tools/cache",
+    "k8s.io/client-go/tools/clientcmd",
+    "k8s.io/client-go/tools/record",
+    "k8s.io/client-go/util/flowcontrol",
+    "k8s.io/client-go/util/jsonpath",
+    "k8s.io/client-go/util/workqueue",
+    "k8s.io/code-generator/cmd/client-gen",
+    "k8s.io/klog",
+    "k8s.io/kube-openapi/cmd/openapi-gen",
+    "k8s.io/kube-openapi/pkg/common",
+    "k8s.io/kubectl/pkg/cmd/testing",
+    "k8s.io/kubernetes/cmd/kubeadm/app/util",
+    "k8s.io/kubernetes/pkg/apis/core/v1",
+    "k8s.io/kubernetes/pkg/controller",
+    "k8s.io/kubernetes/pkg/util/hash",
+    "k8s.io/kubernetes/pkg/util/labels",
+    "k8s.io/kubernetes/pkg/util/node",
+    "k8s.io/kubernetes/pkg/util/workqueue/prometheus",
+    "k8s.io/utils/pointer",
+  ]
+  solver-name = "gps-cdcl"
+  solver-version = 1
diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go
index 928903062..74034bc5a 100644
--- a/cmd/rollouts-controller/main.go
+++ b/cmd/rollouts-controller/main.go
@@ -19,11 +19,13 @@ import (
 	"k8s.io/klog"
 
 	"github.com/argoproj/argo-rollouts/controller"
+	"github.com/argoproj/argo-rollouts/controller/metrics"
 	jobprovider "github.com/argoproj/argo-rollouts/metricproviders/job"
 	clientset "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned"
 	informers "github.com/argoproj/argo-rollouts/pkg/client/informers/externalversions"
 	"github.com/argoproj/argo-rollouts/pkg/signals"
 	controllerutil "github.com/argoproj/argo-rollouts/utils/controller"
+	kubeclientmetrics "github.com/argoproj/argo-rollouts/utils/kubeclientmetrics"
 )
 
 const (
@@ -71,6 +73,8 @@ func newCommand() *cobra.Command {
 				namespace = configNS
 				log.Infof("Using namespace %s", namespace)
 			}
+			k8sRequestProvider := &metrics.K8sRequestsCountProvider{}
+			kubeclientmetrics.AddMetricsTransportWrapper(config, k8sRequestProvider.IncKubernetesRequest)
 
 			kubeClient, err := kubernetes.NewForConfig(config)
 			checkError(err)
@@ -113,6 +117,7 @@ func newCommand() *cobra.Command {
 				resyncDuration,
 				instanceID,
 				metricsPort,
+				k8sRequestProvider,
 				defaultIstioVersion)
 
 			// notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(stopCh)
diff --git a/controller/controller.go b/controller/controller.go
index 5479a1722..19485f05b 100644
--- a/controller/controller.go
+++ b/controller/controller.go
@@ -93,6 +93,7 @@ func NewManager(
 	resyncPeriod time.Duration,
 	instanceID string,
 	metricsPort int,
+	k8sRequestProvider *metrics.K8sRequestsCountProvider,
 	defaultIstioVersion string,
 ) *Manager {
 
@@ -107,14 +108,17 @@ func NewManager(
 	eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")})
 	recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
 	metricsAddr := fmt.Sprintf("0.0.0.0:%d", metricsPort)
+	metricsServer := metrics.NewMetricsServer(
+		metricsAddr,
+		rolloutsInformer.Lister(),
+		k8sRequestProvider,
+	)
 
 	rolloutWorkqueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Rollouts")
 	experimentWorkqueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Experiments")
 	analysisRunWorkqueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "AnalysisRuns")
 	serviceWorkqueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Services")
 
-	metricsServer := metrics.NewMetricsServer(metricsAddr, rolloutsInformer.Lister())
-
 	rolloutController := rollout.NewRolloutController(
 		namespace,
 		kubeclientset,
diff --git a/controller/metrics/client.go b/controller/metrics/client.go
new file mode 100644
index 000000000..97f3ca430
--- /dev/null
+++ b/controller/metrics/client.go
@@ -0,0 +1,53 @@
+package metrics
+
+import (
+	"strconv"
+
+	"github.com/prometheus/client_golang/prometheus"
+
+	kubeclientmetrics "github.com/argoproj/argo-rollouts/utils/kubeclientmetrics"
+)
+
+const (
+	clientsetMetricsNamespace = "controller_clientset"
+)
+
+type K8sRequestsCountProvider struct {
+	k8sRequestsCount *prometheus.CounterVec
+}
+
+func (f *K8sRequestsCountProvider) Register(registerer prometheus.Registerer) {
+	f.k8sRequestsCount = k8sRequestsCount
+	registerer.MustRegister(f.k8sRequestsCount)
+}
+
+var (
+	// Custom events metric
+	k8sRequestsCount = prometheus.NewCounterVec(
+		prometheus.CounterOpts{
+			Namespace: clientsetMetricsNamespace,
+			Name:      "k8s_request_total",
+			Help:      "Number of kubernetes requests executed during application reconciliation.",
+		},
+		[]string{"kind", "namespace", "name", "verb", "status_code"},
+	)
+)
+
+// IncKubernetesRequest increments the kubernetes client counter
+func (m *K8sRequestsCountProvider) IncKubernetesRequest(resourceInfo kubeclientmetrics.ResourceInfo) error {
+	name := resourceInfo.Name
+	namespace := resourceInfo.Namespace
+	kind := resourceInfo.Kind
+	statusCode := strconv.Itoa(resourceInfo.StatusCode)
+	if resourceInfo.Verb == kubeclientmetrics.List {
+		name = "N/A"
+	}
+	if resourceInfo.Verb == kubeclientmetrics.Unknown {
+		namespace = "Unknown"
+		name = "Unknown"
+		kind = "Unknown"
+	}
+
+	m.k8sRequestsCount.WithLabelValues(kind, namespace, name, string(resourceInfo.Verb), statusCode).Inc()
+	return nil
+}
diff --git a/controller/metrics/metrics.go b/controller/metrics/metrics.go
index 6b1c30a64..62413869c 100644
--- a/controller/metrics/metrics.go
+++ b/controller/metrics/metrics.go
@@ -2,15 +2,17 @@ package metrics
 
 import (
 	"net/http"
+	"time"
 
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
 	log "github.com/sirupsen/logrus"
 	"k8s.io/apimachinery/pkg/labels"
 
-	"time"
+	// make sure to register workqueue prometheus metrics
+	_ "k8s.io/kubernetes/pkg/util/workqueue/prometheus"
 
-	v1alpha1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
+	"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
 	rolloutlister "github.com/argoproj/argo-rollouts/pkg/client/listers/rollouts/v1alpha1"
 	"github.com/argoproj/argo-rollouts/utils/conditions"
 	"github.com/argoproj/argo-rollouts/utils/defaults"
@@ -20,6 +22,7 @@ type MetricsServer struct {
 	*http.Server
 	reconcileHistogram *prometheus.HistogramVec
 	errorCounter       *prometheus.CounterVec
+	k8sRequestsCounter *K8sRequestsCountProvider
 }
 
 const (
@@ -78,10 +81,15 @@ const (
 )
 
 // NewMetricsServer returns a new prometheus server which collects rollout metrics
-func NewMetricsServer(addr string, rolloutLister rolloutlister.RolloutLister) *MetricsServer {
+func NewMetricsServer(addr string, rolloutLister rolloutlister.RolloutLister, k8sRequestProvider *K8sRequestsCountProvider) *MetricsServer {
 	mux := http.NewServeMux()
 	rolloutRegistry := NewRolloutRegistry(rolloutLister)
-	mux.Handle(MetricsPath, promhttp.HandlerFor(rolloutRegistry, promhttp.HandlerOpts{}))
+	mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{
+		// contains app controller specific metrics
+		rolloutRegistry,
+		// contains process, golang and controller workqueues metrics
+		prometheus.DefaultGatherer,
+	}, promhttp.HandlerOpts{}))
 
 	reconcileHistogram := prometheus.NewHistogramVec(
 		prometheus.HistogramOpts{
@@ -91,7 +99,7 @@ func NewMetricsServer(addr string, rolloutLister rolloutlister.RolloutLister) *M
 		},
 		append(descRolloutWithStrategyLabels),
 	)
-
+	k8sRequestProvider.Register(rolloutRegistry)
 	rolloutRegistry.MustRegister(reconcileHistogram)
 
 	errorCounter := prometheus.NewCounterVec(
@@ -111,6 +119,7 @@ func NewMetricsServer(addr string, rolloutLister rolloutlister.RolloutLister) *M
 		},
 		reconcileHistogram: reconcileHistogram,
 		errorCounter:       errorCounter,
+		k8sRequestsCounter: k8sRequestProvider,
 	}
 }
 
@@ -164,8 +173,6 @@ func NewRolloutCollector(rolloutLister rolloutlister.RolloutLister) prometheus.C
 func NewRolloutRegistry(rolloutLister rolloutlister.RolloutLister) *prometheus.Registry {
 	registry := prometheus.NewRegistry()
 	registry.MustRegister(NewRolloutCollector(rolloutLister))
-	registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
-	registry.MustRegister(prometheus.NewGoCollector())
 	return registry
 }
 
diff --git a/go.mod b/go.mod
index b2fcd6ae0..3c8079023 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
 	github.com/googleapis/gnostic v0.2.0 // indirect
 	github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
 	github.com/imdario/mergo v0.3.6 // indirect
-	github.com/jstemmer/go-junit-report v0.9.1 // indirect
+	github.com/jstemmer/go-junit-report v0.9.1
 	github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a
 	github.com/lunixbochs/vtclean v1.0.0 // indirect
 	github.com/mattn/go-colorable v0.1.4 // indirect
diff --git a/go.sum b/go.sum
index ca3b271ae..daf63ead0 100644
--- a/go.sum
+++ b/go.sum
@@ -34,7 +34,9 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/antlr/antlr4 v0.0.0-20191011202612-ad2bd05285ca h1:QHbltbNkVcw97h4zA/L8gA4o3dJiFvBZ0gyZHrYXHbs=
 github.com/antlr/antlr4 v0.0.0-20191011202612-ad2bd05285ca/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
@@ -566,6 +568,7 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
 google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
diff --git a/utils/kubeclientmetrics/metric.go b/utils/kubeclientmetrics/metric.go
new file mode 100644
index 000000000..c76e7cbd7
--- /dev/null
+++ b/utils/kubeclientmetrics/metric.go
@@ -0,0 +1,227 @@
+package kubeclientmetrics
+
+import (
+	"io/ioutil"
+	"net/http"
+	"path"
+	"regexp"
+	"strings"
+
+	log "github.com/sirupsen/logrus"
+	"k8s.io/client-go/rest"
+
+	"github.com/argoproj/argo-rollouts/utils/unstructured"
+)
+
+type K8sRequestVerb string
+
+const (
+	List    K8sRequestVerb = "List"
+	Get     K8sRequestVerb = "Get"
+	Create  K8sRequestVerb = "Create"
+	Update  K8sRequestVerb = "Update"
+	Patch   K8sRequestVerb = "Patch"
+	Delete  K8sRequestVerb = "Delete"
+	Unknown K8sRequestVerb = "Unknown"
+)
+
+const findPathRegex = `/v\d\w*?(/[a-zA-Z0-9-]*)(/[a-zA-Z0-9-]*)?(/[a-zA-Z0-9-]*)?(/[a-zA-Z0-9-]*)?`
+
+type ResourceInfo struct {
+	Kind       string
+	Namespace  string
+	Name       string
+	Verb       K8sRequestVerb
+	StatusCode int
+}
+
+func (ri ResourceInfo) HasAllFields() bool {
+	return ri.Kind != "" && ri.Namespace != "" && ri.Name != "" && ri.Verb != "" && ri.StatusCode != 0
+}
+
+type metricsRoundTripper struct {
+	roundTripper http.RoundTripper
+	inc          func(ResourceInfo) error
+	processPath  *regexp.Regexp
+}
+
+// isGetOrList Uses a path from a request to determine if the request is a GET or LIST. The function tries to find an
+// API version within the path and then calculates how many remaining segments are after the API version. A LIST request
+// has segments for the kind with a namespace and the specific namespace if the kind is a namespaced resource.
+// Meanwhile a GET request has an additional segment for resource name. As a result, a LIST has an odd number of
+// segments while a GET request has an even number of segments.
+func (m metricsRoundTripper) isGetOrList(r *http.Request) K8sRequestVerb {
+	segments := m.processPath.FindStringSubmatch(r.URL.Path)
+	unusedGroup := 0
+	for _, str := range segments {
+		if str == "" {
+			unusedGroup++
+		}
+	}
+	if unusedGroup%2 == 1 {
+		return List
+	}
+	return Get
+}
+
+func (m metricsRoundTripper) resolveK8sRequestVerb(r *http.Request) K8sRequestVerb {
+	if r.Method == "POST" {
+		return Create
+	}
+	if r.Method == "DELETE" {
+		return Delete
+	}
+	if r.Method == "PATCH" {
+		return Patch
+	}
+	if r.Method == "PUT" {
+		return Update
+	}
+	if r.Method == "GET" {
+		return m.isGetOrList(r)
+	}
+	return Unknown
+}
+
+func handleList(r *http.Request, statusCode int) ResourceInfo {
+	path := strings.Split(r.URL.Path, "/")
+	len := len(path)
+	kind := path[len-1]
+	namespace := path[len-2]
+	return ResourceInfo{
+		Kind:       kind,
+		Namespace:  namespace,
+		Verb:       List,
+		StatusCode: statusCode,
+	}
+}
+
+func handleGet(r *http.Request, statusCode int) ResourceInfo {
+	path := strings.Split(r.URL.Path, "/")
+	len := len(path)
+	name := path[len-1]
+	kind := path[len-2]
+	namespace := path[len-3]
+	return ResourceInfo{
+		Kind:       kind,
+		Namespace:  namespace,
+		Name:       name,
+		Verb:       Get,
+		StatusCode: statusCode,
+	}
+}
+
+func handleCreate(r *http.Request, statusCode int) ResourceInfo {
+	kind := path.Base(r.URL.Path)
+	bodyIO, err := r.GetBody()
+	if err != nil {
+		log.WithField("Kind", kind).Warn("Unable to Process Create request")
+		return ResourceInfo{}
+	}
+	body, err := ioutil.ReadAll(bodyIO)
+	if err != nil {
+		log.WithField("Kind", kind).Warn("Unable to Process Create request")
+		return ResourceInfo{}
+	}
+	obj, err := unstructured.StrToUnstructured(string(body))
+	if err != nil {
+		log.WithField("Kind", kind).Warn("Unable to Process Create request")
+		return ResourceInfo{}
+	}
+	return ResourceInfo{
+		Kind:       kind,
+		Namespace:  obj.GetNamespace(),
+		Name:       obj.GetName(),
+		Verb:       Create,
+		StatusCode: statusCode,
+	}
+}
+
+func handleDelete(r *http.Request, statusCode int) ResourceInfo {
+	path := strings.Split(r.URL.Path, "/")
+	len := len(path)
+	name := path[len-1]
+	kind := path[len-2]
+	namespace := path[len-3]
+	return ResourceInfo{
+		Kind:       kind,
+		Namespace:  namespace,
+		Name:       name,
+		Verb:       Delete,
+		StatusCode: statusCode,
+	}
+}
+
+func handlePatch(r *http.Request, statusCode int) ResourceInfo {
+	path := strings.Split(r.URL.Path, "/")
+	len := len(path)
+	name := path[len-1]
+	kind := path[len-2]
+	namespace := path[len-3]
+	return ResourceInfo{
+		Kind:       kind,
+		Namespace:  namespace,
+		Name:       name,
+		Verb:       Patch,
+		StatusCode: statusCode,
+	}
+}
+
+func handleUpdate(r *http.Request, statusCode int) ResourceInfo {
+	path := strings.Split(r.URL.Path, "/")
+	len := len(path)
+	name := path[len-1]
+	kind := path[len-2]
+	namespace := path[len-3]
+	return ResourceInfo{
+		Kind:       kind,
+		Namespace:  namespace,
+		Name:       name,
+		Verb:       Update,
+		StatusCode: statusCode,
+	}
+}
+
+func (mrt *metricsRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
+	resp, roundTimeErr := mrt.roundTripper.RoundTrip(r)
+	var info ResourceInfo
+	switch verb := mrt.resolveK8sRequestVerb(r); verb {
+	case List:
+		info = handleList(r, resp.StatusCode)
+	case Get:
+		info = handleGet(r, resp.StatusCode)
+	case Create:
+		info = handleCreate(r, resp.StatusCode)
+	case Delete:
+		info = handleDelete(r, resp.StatusCode)
+	case Patch:
+		info = handlePatch(r, resp.StatusCode)
+	case Update:
+		info = handleUpdate(r, resp.StatusCode)
+	default:
+		log.WithField("path", r.URL.Path).WithField("method", r.Method).Warnf("Unknown Request")
+		info = ResourceInfo{
+			Verb:       Unknown,
+			StatusCode: resp.StatusCode,
+		}
+	}
+	mrt.inc(info)
+	return resp, roundTimeErr
+}
+
+// AddMetricsTransportWrapper adds a transport wrapper which wraps a function call around each kubernetes request
+func AddMetricsTransportWrapper(config *rest.Config, incFunc func(ResourceInfo) error) *rest.Config {
+	regex := regexp.MustCompile(findPathRegex)
+	wrap := config.WrapTransport
+	config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
+		if wrap != nil {
+			rt = wrap(rt)
+		}
+		return &metricsRoundTripper{
+			roundTripper: rt,
+			inc:          incFunc,
+			processPath:  regex,
+		}
+	}
+	return config
+}
diff --git a/utils/unstructured/unstructured.go b/utils/unstructured/unstructured.go
new file mode 100644
index 000000000..63aac36d9
--- /dev/null
+++ b/utils/unstructured/unstructured.go
@@ -0,0 +1,24 @@
+package unstructured
+
+import (
+	"github.com/ghodss/yaml"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+)
+
+func StrToUnstructuredUnsafe(jsonStr string) *unstructured.Unstructured {
+	obj := make(map[string]interface{})
+	err := yaml.Unmarshal([]byte(jsonStr), &obj)
+	if err != nil {
+		panic(err)
+	}
+	return &unstructured.Unstructured{Object: obj}
+}
+
+func StrToUnstructured(jsonStr string) (*unstructured.Unstructured, error) {
+	obj := make(map[string]interface{})
+	err := yaml.Unmarshal([]byte(jsonStr), &obj)
+	if err != nil {
+		return nil, err
+	}
+	return &unstructured.Unstructured{Object: obj}, nil
+}


Test patch:
diff --git a/analysis/controller_test.go b/analysis/controller_test.go
index bc692a26c..1ac4b3ca6 100644
--- a/analysis/controller_test.go
+++ b/analysis/controller_test.go
@@ -95,7 +95,7 @@ func (f *fixture) newController(resync resyncFunc) (*AnalysisController, informe
 		jobI.Batch().V1().Jobs(),
 		resync(),
 		analysisRunWorkqueue,
-		metrics.NewMetricsServer("localhost:8080", i.Argoproj().V1alpha1().Rollouts().Lister()),
+		metrics.NewMetricsServer("localhost:8080", i.Argoproj().V1alpha1().Rollouts().Lister(), &metrics.K8sRequestsCountProvider{}),
 		&record.FakeRecorder{})
 
 	c.enqueueAnalysis = func(obj interface{}) {
diff --git a/controller/metrics/client_test.go b/controller/metrics/client_test.go
new file mode 100644
index 000000000..6d5945d49
--- /dev/null
+++ b/controller/metrics/client_test.go
@@ -0,0 +1,42 @@
+package metrics
+
+import (
+	"log"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	kubeclientmetrics "github.com/argoproj/argo-rollouts/utils/kubeclientmetrics"
+)
+
+const expectedKubernetesRequest = `# TYPE controller_clientset_k8s_request_total counter
+controller_clientset_k8s_request_total{kind="Unknown",name="Unknown",namespace="Unknown",status_code="200",verb="Unknown"} 1
+controller_clientset_k8s_request_total{kind="replicasets",name="N/A",namespace="default",status_code="200",verb="List"} 1`
+
+func TestIncKubernetesRequest(t *testing.T) {
+	cancel, rolloutLister := newFakeLister(noRollouts)
+	defer cancel()
+	provider := &K8sRequestsCountProvider{}
+	metricsServ := NewMetricsServer("localhost:8080", rolloutLister, provider)
+	provider.IncKubernetesRequest(kubeclientmetrics.ResourceInfo{
+		Kind:       "replicasets",
+		Namespace:  "default",
+		Name:       "test",
+		Verb:       kubeclientmetrics.List,
+		StatusCode: 200,
+	})
+	provider.IncKubernetesRequest(kubeclientmetrics.ResourceInfo{
+		Verb:       kubeclientmetrics.Unknown,
+		StatusCode: 200,
+	})
+	req, err := http.NewRequest("GET", "/metrics", nil)
+	assert.NoError(t, err)
+	rr := httptest.NewRecorder()
+	metricsServ.Handler.ServeHTTP(rr, req)
+	assert.Equal(t, rr.Code, http.StatusOK)
+	body := rr.Body.String()
+	log.Println(body)
+	assertMetricsPrinted(t, expectedKubernetesRequest, body)
+}
diff --git a/controller/metrics/metrics_test.go b/controller/metrics/metrics_test.go
index 90d33b403..08632fe5c 100644
--- a/controller/metrics/metrics_test.go
+++ b/controller/metrics/metrics_test.go
@@ -40,6 +40,9 @@ func newFakeLister(fakeRollout ...string) (context.CancelFunc, lister.RolloutLis
 	defer cancel()
 	var fakeRollouts []runtime.Object
 	for _, name := range fakeRollout {
+		if name == "" {
+			continue
+		}
 		fakeRollouts = append(fakeRollouts, newFakeRollout(name))
 	}
 	appClientset := clientset.NewSimpleClientset(fakeRollouts...)
@@ -55,7 +58,7 @@ func newFakeLister(fakeRollout ...string) (context.CancelFunc, lister.RolloutLis
 func testRolloutDescribe(t *testing.T, fakeRollout string, expectedResponse string) {
 	cancel, rolloutLister := newFakeLister(fakeRollout)
 	defer cancel()
-	metricsServ := NewMetricsServer("localhost:8080", rolloutLister)
+	metricsServ := NewMetricsServer("localhost:8080", rolloutLister, &K8sRequestsCountProvider{})
 	req, err := http.NewRequest("GET", "/metrics", nil)
 	assert.NoError(t, err)
 	rr := httptest.NewRecorder()
@@ -71,7 +74,9 @@ type testCombination struct {
 	expectedResponse string
 }
 
-const fakeRollout = `
+const (
+	noRollouts  = ""
+	fakeRollout = `
 apiVersion: argoproj.io/v1alpha1
 kind: Rollout
 metadata:
@@ -100,7 +105,7 @@ spec:
       activeService: active-service
       previewService: preview-service
 `
-
+)
 const expectedResponse = `# HELP rollout_created_time Creation time in unix timestamp for an rollout.
 # TYPE rollout_created_time gauge
 rollout_created_time{name="guestbook-bluegreen",namespace="default",strategy="blueGreen"} -6.21355968e+10
diff --git a/experiments/controller_test.go b/experiments/controller_test.go
index a266bc9b9..2a54de8cc 100644
--- a/experiments/controller_test.go
+++ b/experiments/controller_test.go
@@ -320,7 +320,7 @@ func (f *fixture) newController(resync resyncFunc) (*ExperimentController, infor
 		resync(),
 		rolloutWorkqueue,
 		experimentWorkqueue,
-		metrics.NewMetricsServer("localhost:8080", i.Argoproj().V1alpha1().Rollouts().Lister()),
+		metrics.NewMetricsServer("localhost:8080", i.Argoproj().V1alpha1().Rollouts().Lister(), &metrics.K8sRequestsCountProvider{}),
 		&record.FakeRecorder{})
 
 	var enqueuedObjectsLock sync.Mutex
diff --git a/rollout/controller_test.go b/rollout/controller_test.go
index 6a8506d9b..82755c7e9 100644
--- a/rollout/controller_test.go
+++ b/rollout/controller_test.go
@@ -386,7 +386,7 @@ func (f *fixture) newController(resync resyncFunc) (*RolloutController, informer
 		resync(),
 		rolloutWorkqueue,
 		serviceWorkqueue,
-		metrics.NewMetricsServer("localhost:8080", i.Argoproj().V1alpha1().Rollouts().Lister()),
+		metrics.NewMetricsServer("localhost:8080", i.Argoproj().V1alpha1().Rollouts().Lister(), &metrics.K8sRequestsCountProvider{}),
 		&record.FakeRecorder{},
 		"v1alpha3",
 	)
diff --git a/service/service_test.go b/service/service_test.go
index db2b2af30..3cc8eb4d4 100644
--- a/service/service_test.go
+++ b/service/service_test.go
@@ -51,7 +51,7 @@ func newFakeServiceController(svc *corev1.Service, rollout *v1alpha1.Rollout) (*
 		0,
 		rolloutWorkqueue,
 		serviceWorkqueue,
-		metrics.NewMetricsServer("localhost:8080", i.Argoproj().V1alpha1().Rollouts().Lister()))
+		metrics.NewMetricsServer("localhost:8080", i.Argoproj().V1alpha1().Rollouts().Lister(), &metrics.K8sRequestsCountProvider{}))
 	enqueuedObjects := map[string]int{}
 	c.enqueueRollout = func(obj interface{}) {
 		var key string
diff --git a/utils/controller/controller_test.go b/utils/controller/controller_test.go
index c71e7441a..4191c9f25 100644
--- a/utils/controller/controller_test.go
+++ b/utils/controller/controller_test.go
@@ -32,7 +32,7 @@ import (
 func TestProcessNextWorkItemHandlePanic(t *testing.T) {
 	q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Rollouts")
 	q.Add("valid/key")
-	metricServer := metrics.NewMetricsServer("localhost:8080", nil)
+	metricServer := metrics.NewMetricsServer("localhost:8080", nil, &metrics.K8sRequestsCountProvider{})
 	syncHandler := func(key string) error {
 		panic("Bad big panic :(")
 	}
@@ -78,7 +78,7 @@ func TestProcessNextWorkItemNormalSync(t *testing.T) {
 func TestProcessNextWorkItemSyncHandlerReturnError(t *testing.T) {
 	q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Rollouts")
 	q.Add("valid/key")
-	metricServer := metrics.NewMetricsServer("localhost:8080", nil)
+	metricServer := metrics.NewMetricsServer("localhost:8080", nil, &metrics.K8sRequestsCountProvider{})
 	syncHandler := func(key string) error {
 		return fmt.Errorf("error message")
 	}
diff --git a/utils/kubeclientmetrics/metric_test.go b/utils/kubeclientmetrics/metric_test.go
new file mode 100644
index 000000000..9304bae56
--- /dev/null
+++ b/utils/kubeclientmetrics/metric_test.go
@@ -0,0 +1,300 @@
+package kubeclientmetrics
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"regexp"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	appsv1 "k8s.io/api/apps/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/rest"
+)
+
+type fakeWrapper struct {
+	t             *testing.T
+	currentCount  int
+	expectedCount int
+}
+
+func (f fakeWrapper) RoundTrip(r *http.Request) (*http.Response, error) {
+	resp := httptest.NewRecorder()
+	resp.Code = 201
+	assert.Equal(f.t, f.currentCount, f.expectedCount)
+	return resp.Result(), nil
+}
+
+// TestWrappingTwice Ensures that the config doesn't lose any previous wrappers and the previous wrapper
+// gets executed first
+func TestAddMetricsTransportWrapperWrapTwice(t *testing.T) {
+	config := &rest.Config{
+		Host: "",
+	}
+	currentCount := 0
+	config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
+		return fakeWrapper{
+			t:             t,
+			expectedCount: 0,
+			currentCount:  currentCount,
+		}
+	}
+
+	newConfig := AddMetricsTransportWrapper(config, func(info ResourceInfo) error {
+		currentCount++
+		return nil
+	})
+
+	client := kubernetes.NewForConfigOrDie(newConfig)
+	client.AppsV1().ReplicaSets(metav1.NamespaceDefault).Get("test", metav1.GetOptions{})
+	// Ensures second wrapper added by AddMetricsTransportWrapper is executed
+	assert.Equal(t, 1, currentCount)
+
+}
+
+func TestResolveK8sRequestVerb(t *testing.T) {
+	regex := regexp.MustCompile(findPathRegex)
+	m := metricsRoundTripper{
+		processPath: regex,
+	}
+
+	request := func(str string) *http.Request {
+		requestURL, err := url.Parse(str)
+		if err != nil {
+			panic(err)
+		}
+		return &http.Request{
+			Method: "GET",
+			URL:    requestURL,
+		}
+	}
+	t.Run("Pod LIST", func(t *testing.T) {
+		r := request("https://127.0.0.1/api/v1/namespaces/default/pods")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, List, verb)
+	})
+	t.Run("Pod GET", func(t *testing.T) {
+		r := request("https://127.0.0.1/api/v1/namespaces/default/pods/pod-name-123456")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, Get, verb)
+	})
+	t.Run("Namespace LIST", func(t *testing.T) {
+		r := request("https://127.0.0.1/api/v1/namespaces")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, List, verb)
+	})
+	t.Run("Namespace GET", func(t *testing.T) {
+		r := request("https://127.0.0.1/api/v1/namespaces/default")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, Get, verb)
+	})
+	t.Run("ReplicaSet LIST", func(t *testing.T) {
+		r := request("https://127.0.0.1/apis/extensions/v1beta1/namespaces/default/replicasets")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, List, verb)
+	})
+	t.Run("ReplicaSet GET", func(t *testing.T) {
+		r := request("https://127.0.0.1/apis/extensions/v1beta1/namespaces/default/replicasets/rs-abc123")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, Get, verb)
+	})
+	t.Run("VirtualService LIST", func(t *testing.T) {
+		r := request("https://127.0.0.1/apis/networking.istio.io/v1alpha3/namespaces/default/virtualservices")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, List, verb)
+	})
+	t.Run("VirtualService GET", func(t *testing.T) {
+		r := request("https://127.0.0.1/apis/networking.istio.io/v1alpha3/namespaces/default/virtualservices/virutal-service")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, Get, verb)
+	})
+	t.Run("ClusterRole LIST", func(t *testing.T) {
+		r := request("https://127.0.0.1/apis/rbac.authorization.k8s.io/v1/clusterroles")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, List, verb)
+	})
+	t.Run("ClusterRole GET", func(t *testing.T) {
+		r := request("https://127.0.0.1/apis/rbac.authorization.k8s.io/v1/clusterroles/argo-rollouts-clusterrole")
+		verb := m.resolveK8sRequestVerb(r)
+		assert.Equal(t, Get, verb)
+	})
+}
+
+func TestGetRequest(t *testing.T) {
+	expectedStatusCode := 201
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(expectedStatusCode)
+	}))
+	defer ts.Close()
+	executed := false
+	config := &rest.Config{
+		Host: ts.URL,
+	}
+	newConfig := AddMetricsTransportWrapper(config, func(info ResourceInfo) error {
+		assert.Equal(t, expectedStatusCode, info.StatusCode)
+		assert.Equal(t, "replicasets", info.Kind)
+		assert.Equal(t, metav1.NamespaceDefault, info.Namespace)
+		assert.Equal(t, "test", info.Name)
+		assert.Equal(t, Get, info.Verb)
+		executed = true
+		return nil
+	})
+	client := kubernetes.NewForConfigOrDie(newConfig)
+	client.AppsV1().ReplicaSets(metav1.NamespaceDefault).Get("test", metav1.GetOptions{})
+	assert.True(t, executed)
+}
+
+func TestListRequest(t *testing.T) {
+	expectedStatusCode := 201
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(expectedStatusCode)
+	}))
+	defer ts.Close()
+	executed := false
+	config := &rest.Config{
+		Host: ts.URL,
+	}
+	newConfig := AddMetricsTransportWrapper(config, func(info ResourceInfo) error {
+		assert.Equal(t, expectedStatusCode, info.StatusCode)
+		assert.Equal(t, "replicasets", info.Kind)
+		assert.Equal(t, metav1.NamespaceDefault, info.Namespace)
+		assert.Equal(t, "", info.Name)
+		assert.Equal(t, List, info.Verb)
+		executed = true
+		return nil
+	})
+	client := kubernetes.NewForConfigOrDie(newConfig)
+	client.AppsV1().ReplicaSets(metav1.NamespaceDefault).List(metav1.ListOptions{})
+	assert.True(t, executed)
+}
+
+func TestCreateRequest(t *testing.T) {
+	expectedStatusCode := 201
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(expectedStatusCode)
+	}))
+	defer ts.Close()
+	executed := false
+	config := &rest.Config{
+		Host: ts.URL,
+	}
+	newConfig := AddMetricsTransportWrapper(config, func(info ResourceInfo) error {
+		assert.Equal(t, expectedStatusCode, info.StatusCode)
+		assert.Equal(t, "replicasets", info.Kind)
+		assert.Equal(t, metav1.NamespaceDefault, info.Namespace)
+		assert.Equal(t, "test", info.Name)
+		assert.Equal(t, Create, info.Verb)
+		executed = true
+		return nil
+	})
+	client := kubernetes.NewForConfigOrDie(newConfig)
+	rs := &appsv1.ReplicaSet{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "test",
+			Namespace: metav1.NamespaceDefault,
+		},
+	}
+	client.AppsV1().ReplicaSets(metav1.NamespaceDefault).Create(rs)
+	assert.True(t, executed)
+}
+
+func TestDeleteRequest(t *testing.T) {
+	expectedStatusCode := 201
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(expectedStatusCode)
+	}))
+	defer ts.Close()
+	executed := false
+	config := &rest.Config{
+		Host: ts.URL,
+	}
+	newConfig := AddMetricsTransportWrapper(config, func(info ResourceInfo) error {
+		assert.Equal(t, expectedStatusCode, info.StatusCode)
+		assert.Equal(t, "replicasets", info.Kind)
+		assert.Equal(t, metav1.NamespaceDefault, info.Namespace)
+		assert.Equal(t, "test", info.Name)
+		assert.Equal(t, Delete, info.Verb)
+		executed = true
+		return nil
+	})
+	client := kubernetes.NewForConfigOrDie(newConfig)
+	client.AppsV1().ReplicaSets(metav1.NamespaceDefault).Delete("test", &metav1.DeleteOptions{})
+	assert.True(t, executed)
+}
+
+func TestPatchRequest(t *testing.T) {
+	expectedStatusCode := 201
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(expectedStatusCode)
+	}))
+	defer ts.Close()
+	executed := false
+	config := &rest.Config{
+		Host: ts.URL,
+	}
+	newConfig := AddMetricsTransportWrapper(config, func(info ResourceInfo) error {
+		assert.Equal(t, expectedStatusCode, info.StatusCode)
+		assert.Equal(t, "replicasets", info.Kind)
+		assert.Equal(t, metav1.NamespaceDefault, info.Namespace)
+		assert.Equal(t, "test", info.Name)
+		assert.Equal(t, Patch, info.Verb)
+		executed = true
+		return nil
+	})
+	client := kubernetes.NewForConfigOrDie(newConfig)
+	client.AppsV1().ReplicaSets(metav1.NamespaceDefault).Patch("test", types.MergePatchType, []byte("{}"))
+	assert.True(t, executed)
+}
+
+func TestUpdateRequest(t *testing.T) {
+	expectedStatusCode := 201
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(expectedStatusCode)
+	}))
+	defer ts.Close()
+	executed := false
+	config := &rest.Config{
+		Host: ts.URL,
+	}
+	newConfig := AddMetricsTransportWrapper(config, func(info ResourceInfo) error {
+		assert.Equal(t, expectedStatusCode, info.StatusCode)
+		assert.Equal(t, "replicasets", info.Kind)
+		assert.Equal(t, metav1.NamespaceDefault, info.Namespace)
+		assert.Equal(t, "test", info.Name)
+		assert.Equal(t, Update, info.Verb)
+		executed = true
+		return nil
+	})
+	client := kubernetes.NewForConfigOrDie(newConfig)
+	rs := &appsv1.ReplicaSet{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "test",
+		},
+	}
+	client.AppsV1().ReplicaSets(metav1.NamespaceDefault).Update(rs)
+	assert.True(t, executed)
+}
+
+func TestUnknownRequest(t *testing.T) {
+	expectedStatusCode := 201
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(expectedStatusCode)
+	}))
+	defer ts.Close()
+	executed := false
+	config := &rest.Config{
+		Host: ts.URL,
+	}
+	newConfig := AddMetricsTransportWrapper(config, func(info ResourceInfo) error {
+		assert.Equal(t, expectedStatusCode, info.StatusCode)
+		assert.Equal(t, Unknown, info.Verb)
+		executed = true
+		return nil
+	})
+	client := kubernetes.NewForConfigOrDie(newConfig)
+	client.Discovery().RESTClient().Verb("invalid-verb").Do()
+	assert.True(t, executed)
+}
diff --git a/utils/unstructured/unstructured_test.go b/utils/unstructured/unstructured_test.go
new file mode 100644
index 000000000..c61109f20
--- /dev/null
+++ b/utils/unstructured/unstructured_test.go
@@ -0,0 +1,58 @@
+package unstructured
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+)
+
+func TestStrToUnstructuredSuccesfully(t *testing.T) {
+	rsStr := `apiVersion: apps/v1
+kind: ReplicaSet
+metadata:
+  name: test
+spec:
+  replicas: 1
+`
+	t.Run("Safe method", func(t *testing.T) {
+		obj, err := StrToUnstructured(rsStr)
+		assert.Nil(t, err)
+		assert.NotNil(t, obj)
+		assert.Equal(t, "test", obj.GetName())
+		assert.Equal(t, "ReplicaSet", obj.GetKind())
+		assert.Equal(t, "apps/v1", obj.GetAPIVersion())
+		replicas, exists, err := unstructured.NestedFloat64(obj.Object, "spec", "replicas")
+		assert.True(t, exists)
+		assert.Nil(t, err)
+		assert.Equal(t, float64(1), replicas)
+	})
+
+	t.Run("Unsafe method", func(t *testing.T) {
+		obj := StrToUnstructuredUnsafe(rsStr)
+		assert.NotNil(t, obj)
+		assert.Equal(t, "test", obj.GetName())
+		assert.Equal(t, "ReplicaSet", obj.GetKind())
+		assert.Equal(t, "apps/v1", obj.GetAPIVersion())
+		replicas, exists, err := unstructured.NestedFloat64(obj.Object, "spec", "replicas")
+		assert.True(t, exists)
+		assert.Nil(t, err)
+		assert.Equal(t, float64(1), replicas)
+	})
+}
+
+func TestStrToUnstructuredFails(t *testing.T) {
+	t.Run("Safe method", func(t *testing.T) {
+		obj, err := StrToUnstructured("{")
+		assert.Nil(t, obj)
+		assert.NotNil(t, err)
+	})
+
+	t.Run("Unsafe method", func(t *testing.T) {
+		var obj *unstructured.Unstructured
+		assert.Panics(t, func() {
+			obj = StrToUnstructuredUnsafe("{")
+		})
+		assert.Nil(t, obj)
+	})
+}