Repository: knative/pkg
Pull request #2016 (2021-02-09 14:57:59)

adding retry event count metric for source
<!-- Thanks for sending a pull request! -->

# Changes

<!-- 
Describe your changes here- ideally you can get that description straight from
your descriptive commit message(s)! 

- :gift: Add new feature
- :bug: Fix bug
- :broom: Update or clean up current behavior
- :wastebasket: Remove feature or internal logic
-->

- adding a code change that will be used by knative/eventing to report retry event count for knative source.

knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/pkg/pull/2016#" title="Author self-approved">kthakar1990</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **n3wscott** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @n3wscott` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative%2Fpkg).

<details open>
Needs approval from an approver in each of these files:

- **[source/OWNERS](https://github.com/knative/pkg/blob/master/source/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["n3wscott"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative/pkg/pull/2016?src=pr&el=h1) Report
> Merging [#2016](https://codecov.io/gh/knative/pkg/pull/2016?src=pr&el=desc) (5537798) into [master](https://codecov.io/gh/knative/pkg/commit/a02dcff9ee2694ab9bbc694bddbd95d3aaae615b?el=desc) (a02dcff) will **increase** coverage by `0.01%`.
> The diff coverage is `81.81%`.

[![Impacted file tree graph](https://codecov.io/gh/knative/pkg/pull/2016/graphs/tree.svg?width=650&height=150&src=pr&token=rlqpDnfxbO)](https://codecov.io/gh/knative/pkg/pull/2016?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #2016      +/-   ##
==========================================
+ Coverage   67.13%   67.14%   +0.01%     
==========================================
  Files         214      214              
  Lines        9097     9108      +11     
==========================================
+ Hits         6107     6116       +9     
- Misses       2715     2716       +1     
- Partials      275      276       +1     
```


| [Impacted Files](https://codecov.io/gh/knative/pkg/pull/2016?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [source/source\_stats\_reporter.go](https://codecov.io/gh/knative/pkg/pull/2016/diff?src=pr&el=tree#diff-c291cmNlL3NvdXJjZV9zdGF0c19yZXBvcnRlci5nbw==) | `84.90% <81.81%> (-0.81%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative/pkg/pull/2016?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/knative/pkg/pull/2016?src=pr&el=footer). Last update [a02dcff...2086c69](https://codecov.io/gh/knative/pkg/pull/2016?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.github/workflows/knative-releasability.yaml b/.github/workflows/knative-releasability.yaml
index cecf0a52f..f9b1799f2 100644
--- a/.github/workflows/knative-releasability.yaml
+++ b/.github/workflows/knative-releasability.yaml
@@ -36,8 +36,8 @@ jobs:
     env:
       #########################################
       #   Update this section each release.   #
-      RELEASE: 'v0.20'
-      SLACK_CHANNEL: 'release-20'
+      RELEASE: 'v0.21'
+      SLACK_CHANNEL: 'release-21'
       #########################################
 
     steps:
@@ -157,3 +157,11 @@ jobs:
             ${{ env.CHECK_MESSAGE }}
             ${{ env.VERIFY_MESSAGE }}
             For detailed logs: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
+
+      - name: Fail if NO-GO
+        if: steps.exists.outputs.release-branch == 'false' && env.current == 'false'
+        run: |
+          # When we have figured out that things are NO-GO, we intentionally fail the job
+          # so that the status badge shows up red and we can use the badges to create a
+          # releasability dashboard for all of the repos.
+          exit 1
diff --git a/.github/workflows/knative-style.yaml b/.github/workflows/knative-style.yaml
index 4e0947a9b..be7ce9a87 100644
--- a/.github/workflows/knative-style.yaml
+++ b/.github/workflows/knative-style.yaml
@@ -100,7 +100,7 @@ jobs:
 
       - name: Install Tools
         env:
-          WOKE_VERSION: v0.4.1
+          WOKE_VERSION: v0.5.0
         run: |
           TEMP_PATH="$(mktemp -d)"
           cd $TEMP_PATH
diff --git a/RELEASE-LEADS.md b/RELEASE-LEADS.md
index 776caf27e..94d190dd1 100644
--- a/RELEASE-LEADS.md
+++ b/RELEASE-LEADS.md
@@ -1,10 +1,15 @@
 # Release Leads
 
+This document includes the roster, instructions and timetable to perform a
+Knative release.
+
 For each release cycle, we dedicate a team of two individuals, one from Eventing
 and one from Serving, to shepherd the release process. Participation is
 voluntary and based on good faith. We are only expected to participate during
 our local office hour.
 
+---
+
 # Roster
 
 We seed this rotation with all approvers from all the Serving and Eventing
@@ -58,113 +63,89 @@ This roster is seeded with all approvers from Eventing workgroups.
 
 **NOTE:** v0.20 is moved by 3 weeks for end of year holidays
 
-# Release instruction
-
-We release the components of Knative every 6 weeks. All of these components must
-be moved to the latest "release" of all shared dependencies prior to each
-release.
-
-## First week of the rotation
-
-### Make sure you have the right permission
-
-Check to make sure you already are in the "Knative Release Leads" team in
-https://github.com/knative/community/blob/master/peribolos/knative.yaml and
-https://github.com/knative/community/blob/master/peribolos/knative-sandbox.yaml
-. If not, send a PR like
-[this one](https://github.com/knative/community/pull/209) to grant yourself some
-super power.
-
-### Create a release Slack channel
-
-Ask someone from the TOC to create a **release-`#`** Slack channel that will be
-used to help manage this release.
-
-## 14 days prior to the release
-
-### Update the Knative releasability defaults
-
-Update the defaults in
-[knative-releasability.yaml](https://github.com/knative-sandbox/.github/blob/1e4e31edfb2181220db744ad0fcb135629e1cb8e/workflow-templates/knative-releasability.yaml#L37-L41)
-to this release. These changes will be propagated to the rest of Knative in the
-next round of workflow syncs.
-
-### Announce the imminent `pkg` cut
-
-Announce on **#general** that `pkg` will be cut in a week.
-
 ---
 
-## 7 days prior to the release
+# Instructions
 
-### Announce the imminent release cut
+Below you'll find the instructions to release a `knative.dev` repository.
 
-Announce on **#general** that the release will be cut in a week and that
-additional caution should be used when merging big changes.
+For more information on the timetable, jump to the [Timetable](#timetable)
+paragraph.
 
-### Collect release-notes
+## Release a repository
 
-Make a new HackMD release notes document.
-[last release notes document](https://hackmd.io/cJwvzJ4eRVeqqiXzOPtxsA), empty
-it out and send it to the WG leads of the respective project (serving or
-eventing) to fill in. Coordinate with both serving and eventing leads.
+Releasing a repository includes:
 
-Each repo has a `Release Notes` GitHub Action workflow. This can be used to
-generate the starting point for the release notes. See an example in
-[Eventing](https://github.com/knative/eventing/actions?query=workflow%3A%22Release+Notes%22).
-The default starting and ending SHAs will work if running out of the `master`
-branch, or you can determin the correct starting and ending SHAs for the script
-to run.
+- Aligning the `knative.dev` dependencies to the other release versions on
+  master
+- Creating a new branch starting from master for the release (e.g.
+  `release-0.20`)
+- Execute the job on Prow that builds the code from the release branch, tags the
+  revision, publishes the images, publishes the yaml artifacts and generates the
+  Github release.
 
-## Cutting release branches
+Most of the above steps are automated, although in some situations it might be
+necessary to perform some of them manually.
 
-If the
-[Releasability](https://github.com/knative/serving/actions?query=workflow%3AReleasability)
-script reports a "GO", then the repo is ready to cut the `release-v.y` branch.
-This can be done by using the GitHub UI:
+### Check the build on master pass
 
-1. Click on the branch selection box at the top level page of the repository.
+Before beginning, check if the repository is in a good shape and the builds pass
+consistently. **This is required** because the Prow job that builds the release
+artifacts will execute all the various tests (build, unit, e2e) and, if
+something goes wrong, you will probably need to restart this process from the
+beginning.
 
-   ![Click the branch selection box](images/github-branch.png)
+For any problems in a specific repo, get in touch with the relevant WG leads to
+fix them.
 
-1. Search for the correct `release-x.y` branch name for the release.
+### Aligning the dependencies
 
-   ![Search for the expected release branch name](images/github-branch-search.png)
+In order to align the `knative.dev` dependencies, knobots will perform PRs like
+[this](https://github.com/knative/eventing/pull/4713) for each repo, executing
+the command `./hack/update-deps.sh --upgrade --release 0.20` and committing all
+the content.
 
-1. Click "Create branch: release-x.y".
+If no dependency bump PR is available, you can:
 
-   ![Click create branch: release-x.y](images/github-branch-create.png)
+- Manually trigger the generation of these PRs starting the
+  [Knobots Auto Updates workflow](https://github.com/knative-sandbox/knobots/actions?query=workflow%3A%22Auto+Updates%22)
+  and wait for the PR to pop in the repo you need.
+- Execute the script below on your machine and PR the result to master:
 
-If the Releasability script reported a "NO-GO", the repo needs to be updated.
-This can be performed by running the the
-[Knobots Auto Updates workflow](https://github.com/knative-sandbox/knobots/actions?query=workflow%3A%22Auto+Updates%22),
-or making a PR to update _master_ from the results of running a manul update
-deps:
+```shell
+RELEASE=0.20
+REPO=git@github.com:knative/example.git
+
+tmpdir=$(dirname $(mktemp -u))
+cd ${tmpdir}
+git clone ${REPO}
+cd "$(basename "${REPO}" .git)"
 
-```bash
-RELEASE=0.19
 ./hack/update-deps.sh --upgrade --release ${RELEASE}
-```
+./hack/update-codegen.sh
 
-After a `release-x.y` branch exists, a 4 hourly prow job will produce the label
-and GitHub Release. Update the description of the release with the release notes
-collected. Can't wait 4 hours?
-[Manually trigger the auto-release job.](#manually-trigger-prow-auto-release-job)
+# If there are no changes, you can go to the next step without committing any change.
+# Otherwise, commit all the changes
+git status
+```
 
-### Manual+Local Release Branch Creation
+### Releasability
 
-If you need or want to perform the release branch cutting process locally, here
-is how:
+At this point, you can proceed with the releasability check. A releasability
+check is executed periodically and posts the result on the Slack release channel
+and it fails if the dependencies are not properly aligned. If you don't want to
+wait, you can manually execute the
+[Releasability workflow](https://github.com/knative/serving/actions?query=workflow%3AReleasability).
 
-_Prerequisite_: Install the
-[**buoy** tool](https://github.com/knative/test-infra/tree/master/buoy).
+If the releasability reports NO-GO, probably there is some deps misalignment,
+hence you need to go back to the previous step and check the dependencies,
+otherwise, you're ready to proceed.
 
-We have staged releasibility status checks that are sent to the release Slack
-channel to give alerts when things are ready to go. You can manually run that
-for each repo before cutting the release branch,
+You can execute the releasability check locally using
+[**buoy**](https://github.com/knative/test-infra/tree/master/buoy):
 
 ```bash
-RELEASE=0.19
+RELEASE=0.20
 REPO=git@github.com:knative/example.git
 
 tmpdir=$(dirname $(mktemp -u))
@@ -175,28 +156,54 @@ cd "$(basename "${REPO}" .git)"
 if buoy check go.mod --domain knative.dev --release ${RELEASE} --verbose; then
   git checkout -b release-${RELEASE}
   ./hack/update-deps.sh --upgrade --release ${RELEASE}
-  # consistency check, shouldnt do anything
-  echo "There should be no changes to git:"
   git status
 fi
 ```
 
-Then to push the release branch if no changes.
+If there are changes, then it's NO-GO, otherwise it's GO
 
-```bash
-git push origin release-${RELEASE}
-```
+### Just one last check before cutting
+
+After the dependencies are aligned and releasability is ready to GO, perform one
+last check manually that every `knative.dev` in the `go.mod` file is properly
+configured:
+
+- For the _support_ repos (`hack`, `test-infra`, `pkg`, etc) you should see the
+  dependency version pointing at a revision which should match the `HEAD` of the
+  release branch. E.g. `knative.dev/pkg v0.0.0-20210112143930-acbf2af596cf`
+  points at the revision `acbf2af596cf`, which is the `HEAD` of the
+  `release-0.20` branch in `pkg` repo.
+- For the _release_ repos, you should see the dependency version pointing at the
+  version tag. E.g. `knative.dev/eventing v0.20.0` points at the tag `v0.20.0`
+  in the `eventing` repo.
+
+### Cut the branch
 
-Otherwise, make a PR to _master_ to update the repo. After that merges then try
-the above script again.
+Now you're ready to create the `release-v.y` branch. This can be done by using
+the GitHub UI:
 
-> _Note_: This assumes the upstream knative github repo is a remote called
-> origin.
+1. Click on the branch selection box at the top level page of the repository.
+
+   ![Click the branch selection box](images/github-branch.png)
+
+1. Search for the correct `release-x.y` branch name for the release.
 
-This should be done for each repo following the dependency chain and required
-timing.
+   ![Search for the expected release branch name](images/github-branch-search.png)
+
+1. Click "Create branch: release-x.y".
+
+   ![Click create branch: release-x.y](images/github-branch-create.png)
 
-### Manually trigger Prow auto-release job.
+Otherwise, you can do it by hand on your local machine.
+
+### The Prow job
+
+After a `release-x.y` branch exists, a 4 hourly prow job will build the code
+from the release branch, tag the revision, publish the images, publish the yaml
+artifacts and generate the Github release. Update the description of the release
+with the release notes collected.
+
+You can manually trigger the release:
 
 1. Navigate to https://prow.knative.dev/
 
@@ -210,24 +217,87 @@ timing.
 
    ![Rerun Prow Auto Release](images/prow-rerun.png)
 
+### Verify nightly release automation is intact
+
+The automation used to cut the actual releases is the very same as the
+automation used to cut nightly releases. Verify via testgrid that all relevant
+nightly releases are passing. If they are not coordinate with the relevant WG
+leads to fix them.
+
+### What could go wrong?
+
+In case you cut a branch before it was ready (e.g. some deps misalignment, a
+failing test, etc), you can try to restart this process. But first, clean up the
+repo in this order:
+
+1. Remove the Github release (if any)
+1. Remove the git tag (if any) using `git push --delete origin v0.20.0`
+   (assuming `origin` is the `knative.dev` repo)
+1. Remove the git branch (if any) from the Github UI
+
+---
+
+# Timetable
+
+We release the components of Knative every 6 weeks. All of these components must
+be moved to the latest "release" of all shared dependencies prior to each
+release.
+
+## First week of the rotation
+
+### Make sure you have the right permission
+
+Check to make sure you already are in the "Knative Release Leads" team in
+https://github.com/knative/community/blob/master/peribolos/knative.yaml and
+https://github.com/knative/community/blob/master/peribolos/knative-sandbox.yaml
+. If not, send a PR like
+[this one](https://github.com/knative/community/pull/209) to grant yourself some
+super power.
+
+### Create a release Slack channel
+
+Ask someone from the TOC to create a **release-`#`** Slack channel that will be
+used to help manage this release.
+
+## 14 days prior to the release
+
+### Update the Knative releasability defaults
+
+Update the defaults in
+[knative-releasability.yaml](https://github.com/knative-sandbox/.github/blob/1e4e31edfb2181220db744ad0fcb135629e1cb8e/workflow-templates/knative-releasability.yaml#L37-L41)
+to this release. These changes will be propagated to the rest of Knative in the
+next round of workflow syncs.
+
+### Announce the imminent `pkg` cut
+
+Announce on **#general** that `pkg` will be cut in a week.
+
 ### Cut release branches of supporting repos
 
-We need to start cutting release branches in each module that does not produce a
-release artifact, but we will do it from least dependent to most dependent.
-Follow the [cutting release branches](#cutting-release-branches) guide, starting
-with the **hack** repo:
+The supporting repos are the base repos where we have common code and common
+scripts. For these repos, we follow the same release process as explained in
+[release a repository](#release-a-repository), but no prow job is executed,
+hence no git tag and Github release are produced.
+
+Follow the [release a repository](#release-a-repository) guide, skipping the
+prow job part, starting with the **hack** repo:
 
 - [knative/hack](https://github.com/knative/hack)
 
 After **hack**:
 
-- [knative/pkg](https://github.com/knative/pkg)
-- [knative/test-infra](https://github.com/knative/test-infra)
+| Repo                                                            | Releasability                                                                             |
+| --------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
+| [knative.dev/pkg](https://github.com/knative/pkg)               | ![Releasability](https://github.com/knative/pkg/workflows/Releasability/badge.svg)        |
+| [knative.dev/test-infra](https://github.com/knative/test-infra) | ![Releasability](https://github.com/knative/test-infra/workflows/Releasability/badge.svg) |
 
 After **pkg**:
 
-- [knative/networking](https://github.com/knative/networking)
-- [knative/caching](https://github.com/knative/caching)
+| Repo                                                                              | Releasability                                                                                          |
+| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
+| [knative.dev/networking](https://github.com/knative/networking)                   | ![Releasability](https://github.com/knative/networking/workflows/Releasability/badge.svg)              |
+| [knative.dev/caching](https://github.com/knative/caching)                         | ![Releasability](https://github.com/knative/caching/workflows/Releasability/badge.svg)                 |
+| [knative.dev/reconciler-test](https://github.com/knative-sandbox/reconciler-test) | ![Releasability](https://github.com/knative-sandbox/reconciler-test/workflows/Releasability/badge.svg) |
 
 Automation will propagate these updates to all the downstream repos in the next
 few cycles. The goal is to have the first wave of repo releases (**serving**,
@@ -235,14 +305,26 @@ few cycles. The goal is to have the first wave of repo releases (**serving**,
 signaled via the Slack report of releasability posted to the **release-`#`**
 channel every morning (5am PST, M-F).
 
-### Verify nightly release automation is intact
+## 7 days prior to the release
 
-The automation used to cut the actual releases is the very same as the
-automation used to cut nightly releases. Verify via testgrid that all relevant
-nightly releases are passing. If they are not coordinate with the relevant WG
-leads to fix them.
+### Announce the imminent release cut
 
----
+Announce on **#general** that the release will be cut in a week and that
+additional caution should be used when merging big changes.
+
+### Collect release-notes
+
+Make a new HackMD release notes document.
+[last release notes document](https://hackmd.io/cJwvzJ4eRVeqqiXzOPtxsA), empty
+it out and send it to the WG leads of the respective project (serving or
+eventing) to fill in. Coordinate with both serving and eventing leads.
+
+Each repo has a `Release Notes` GitHub Action workflow. This can be used to
+generate the starting point for the release notes. See an example in
+[Eventing](https://github.com/knative/eventing/actions?query=workflow%3A%22Release+Notes%22).
+The default starting and ending SHAs will work if running out of the `master`
+branch, or you can determine the correct starting and ending SHAs for the script
+to run.
 
 ## 1 day prior to the release
 
@@ -251,70 +333,76 @@ leads to fix them.
 Confirm with the respective WG leads that the release is imminent and obtain
 green light.
 
----
-
 ## Day of the release
 
-Follow the [cutting release branches](#cutting_release_branches) instructions
-for each repo. Wait for release automation to kick in (runs on a 2 hour
-interval). Once the release automation passed, it will create a release tag in
-the repository. Enhance the respective tags with the collected release-notes
-using the GitHub UI.
+Follow the [release a repository](#release-a-repository) instructions for each
+repo. Wait for release automation to kick in (runs on a 2 hour interval). Once
+the release automation passed, it will create a release tag in the repository.
+Enhance the respective tags with the collected release-notes using the GitHub
+UI.
 
 In general the release dependency order is something like the following (as of
-v0.19). Note: `buoy check` will fail if the dependencies are not yet ready.
+v0.20). Note: `buoy check` will fail if the dependencies are not yet ready.
 
 First:
 
-- [knative/serving](https://github.com/knative/serving)
-- [knative-sandbox/net-certmanager](https://github.com/knative-sandbox/net-certmanager)
-- [knative-sandbox/net-contour](https://github.com/knative-sandbox/net-contour)
-- [knative-sandbox/net-http01](https://github.com/knative-sandbox/net-http01)
-- [knative-sandbox/net-istio](https://github.com/knative-sandbox/net-istio)
-
-- [knative/eventing](https://github.com/knative/eventing)
-- [knative-sandbox/discovery](https://github.com/knative-sandbox/discovery)
-
-- [knative-sandbox/sample-controller](https://github.com/knative-sandbox/sample-controller)
-
-After **serving**:
-
-- [knative-sandbox/net-kourier](https://github.com/knative-sandbox/net-kourier)
+| Repo                                                                                  | Release                                                                                                                                                                   | Releasability                                                                                            | Nightly                                                                                                  |
+| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
+| [knative.dev/serving](https://github.com/knative/serving)                             | [![Releases](https://img.shields.io/github/release-pre/knative/serving.svg?sort=semver)](https://github.com/knative/serving/releases)                                     | ![Releasability](https://github.com/knative/serving/workflows/Releasability/badge.svg)                   | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-serving-nightly-release)                   |
+| [knative.dev/net-certmanager](https://github.com/knative-sandbox/net-certmanager)     | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/net-certmanager.svg?sort=semver)](https://github.com/knative-sandbox/net-certmanager/releases)     | ![Releasability](https://github.com/knative-sandbox/net-certmanager/workflows/Releasability/badge.svg)   | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-net-certmanager-nightly-release)   |
+| [knative.dev/net-contour](https://github.com/knative-sandbox/net-contour)             | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/net-contour.svg?sort=semver)](https://github.com/knative-sandbox/net-contour/releases)             | ![Releasability](https://github.com/knative-sandbox/net-contour/workflows/Releasability/badge.svg)       | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-net-contour-nightly-release)       |
+| [knative.dev/net-http01](https://github.com/knative-sandbox/net-http01)               | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/net-http01.svg?sort=semver)](https://github.com/knative-sandbox/net-http01/releases)               | ![Releasability](https://github.com/knative-sandbox/net-http01/workflows/Releasability/badge.svg)        | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-net-http01-nightly-release)        |
+| [knative.dev/net-istio](https://github.com/knative-sandbox/net-istio)                 | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/net-istio.svg?sort=semver)](https://github.com/knative-sandbox/net-istio/releases)                 | ![Releasability](https://github.com/knative-sandbox/net-istio/workflows/Releasability/badge.svg)         | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-net-istio-nightly-release)         |
+| [knative.dev/net-kourier](https://github.com/knative-sandbox/net-kourier)             | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/net-kourier.svg?sort=semver)](https://github.com/knative-sandbox/net-kourier/releases)             | ![Releasability](https://github.com/knative-sandbox/net-kourier/workflows/Releasability/badge.svg)       | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-net-kourier-nightly-release)       |
+| [knative.dev/eventing](https://github.com/knative/eventing)                           | [![Releases](https://img.shields.io/github/release-pre/knative/eventing.svg?sort=semver)](https://github.com/knative/eventing/releases)                                   | ![Releasability](https://github.com/knative/eventing/workflows/Releasability/badge.svg)                  | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-eventing-nightly-release)                  |
+| [knative.dev/discovery](https://github.com/knative-sandbox/discovery)                 | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/discovery.svg?sort=semver)](https://github.com/knative-sandbox/discovery/releases)                 | ![Releasability](https://github.com/knative-sandbox/discovery/workflows/Releasability/badge.svg)         | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-discovery-nightly-release)         |
+| [knative.dev/sample-controller](https://github.com/knative-sandbox/sample-controller) | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/sample-controller.svg?sort=semver)](https://github.com/knative-sandbox/sample-controller/releases) | ![Releasability](https://github.com/knative-sandbox/sample-controller/workflows/Releasability/badge.svg) | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-sample-controller-nightly-release) |
 
 After **eventing**:
 
-- [knative-sandbox/eventing-awssqs](https://github.com/knative-sandbox/eventing-awssqs)
-- [knative-sandbox/eventing-camel](https://github.com/knative-sandbox/eventing-camel)
-- [knative-sandbox/eventing-ceph](https://github.com/knative-sandbox/eventing-ceph)
-- [knative-sandbox/eventing-couchdb](https://github.com/knative-sandbox/eventing-couchdb)
-- [knative-sandbox/eventing-kafka](https://github.com/knative-sandbox/eventing-kafka)
-- [knative-sandbox/eventing-kafka-broker](https://github.com/knative-sandbox/eventing-kafka-broker)
-- [knative-sandbox/eventing-natss](https://github.com/knative-sandbox/eventing-natss)
-- [knative-sandbox/eventing-prometheus](https://github.com/knative-sandbox/eventing-prometheus)
-- [knative-sandbox/eventing-rabbitmq](https://github.com/knative-sandbox/eventing-rabbitmq)
-- [knative-sandbox/sample-source](https://github.com/knative-sandbox/sample-source)
+| Repo                                                                                          | Release                                                                                                                                                                           | Releasability                                                                                                | Nightly                                                                                                      |
+| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
+| [knative.dev/eventing-awssqs](https://github.com/knative-sandbox/eventing-awssqs)             | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-awssqs.svg?sort=semver)](https://github.com/knative-sandbox/eventing-awssqs/releases)             | ![Releasability](https://github.com/knative-sandbox/eventing-awssqs/workflows/Releasability/badge.svg)       | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-awssqs-nightly-release)       |
+| [knative.dev/eventing-camel](https://github.com/knative-sandbox/eventing-camel)               | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-camel.svg?sort=semver)](https://github.com/knative-sandbox/eventing-camel/releases)               | ![Releasability](https://github.com/knative-sandbox/eventing-camel/workflows/Releasability/badge.svg)        | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-camel-nightly-release)        |
+| [knative.dev/eventing-ceph](https://github.com/knative-sandbox/eventing-ceph)                 | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-ceph.svg?sort=semver)](https://github.com/knative-sandbox/eventing-ceph/releases)                 | ![Releasability](https://github.com/knative-sandbox/eventing-ceph/workflows/Releasability/badge.svg)         | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-ceph-nightly-release)         |
+| [knative.dev/eventing-couchdb](https://github.com/knative-sandbox/eventing-couchdb)           | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-couchdb.svg?sort=semver)](https://github.com/knative-sandbox/eventing-couchdb/releases)           | ![Releasability](https://github.com/knative-sandbox/eventing-couchdb/workflows/Releasability/badge.svg)      | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-couchdb-nightly-release)      |
+| [knative.dev/eventing-kafka](https://github.com/knative-sandbox/eventing-kafka)               | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-kafka.svg?sort=semver)](https://github.com/knative-sandbox/eventing-kafka/releases)               | ![Releasability](https://github.com/knative-sandbox/eventing-kafka/workflows/Releasability/badge.svg)        | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-kafka-nightly-release)        |
+| [knative.dev/eventing-kafka-broker](https://github.com/knative-sandbox/eventing-kafka-broker) | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-kafka-broker.svg?sort=semver)](https://github.com/knative-sandbox/eventing-kafka-broker/releases) | ![Releasability](https://github.com/knative-sandbox/eventing-kafka-broker/workflows/Releasability/badge.svg) | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-kafka-broker-nightly-release) |
+| [knative.dev/eventing-natss](https://github.com/knative-sandbox/eventing-natss)               | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-natss.svg?sort=semver)](https://github.com/knative-sandbox/eventing-natss/releases)               | ![Releasability](https://github.com/knative-sandbox/eventing-natss/workflows/Releasability/badge.svg)        | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-natss-nightly-release)        |
+| [knative.dev/eventing-prometheus](https://github.com/knative-sandbox/eventing-prometheus)     | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-prometheus.svg?sort=semver)](https://github.com/knative-sandbox/eventing-prometheus/releases)     | ![Releasability](https://github.com/knative-sandbox/eventing-prometheus/workflows/Releasability/badge.svg)   | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-prometheus-nightly-release)   |
+| [knative.dev/eventing-rabbitmq](https://github.com/knative-sandbox/eventing-rabbitmq)         | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-rabbitmq.svg?sort=semver)](https://github.com/knative-sandbox/eventing-rabbitmq/releases)         | ![Releasability](https://github.com/knative-sandbox/eventing-rabbitmq/workflows/Releasability/badge.svg)     | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-rabbitmq-nightly-release)     |
+| [knative.dev/sample-source](https://github.com/knative-sandbox/sample-source)                 | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/sample-source.svg?sort=semver)](https://github.com/knative-sandbox/sample-source/releases)                 | ![Releasability](https://github.com/knative-sandbox/sample-source/workflows/Releasability/badge.svg)         | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-sample-source-nightly-release)         |
 
 After both **eventing** and **serving**:
 
-- [knative-sandbox/eventing-redis](https://github.com/knative-sandbox/eventing-redis)
-- [knative-sandbox/eventing-github](https://github.com/knative-sandbox/eventing-github)
-- [knative-sandbox/eventing-gitlab](https://github.com/knative-sandbox/eventing-gitlab)
+| Repo                                                                              | Release                                                                                                                                                               | Releasability                                                                                          | Nightly                                                                                                |
+| --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
+| [knative.dev/eventing-redis](https://github.com/knative-sandbox/eventing-redis)   | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-redis.svg?sort=semver)](https://github.com/knative-sandbox/eventing-redis/releases)   | ![Releasability](https://github.com/knative-sandbox/eventing-redis/workflows/Releasability/badge.svg)  | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-redis-nightly-release)  |
+| [knative.dev/eventing-github](https://github.com/knative-sandbox/eventing-github) | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-github.svg?sort=semver)](https://github.com/knative-sandbox/eventing-github/releases) | ![Releasability](https://github.com/knative-sandbox/eventing-github/workflows/Releasability/badge.svg) | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-github-nightly-release) |
+| [knative.dev/eventing-gitlab](https://github.com/knative-sandbox/eventing-gitlab) | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-gitlab.svg?sort=semver)](https://github.com/knative-sandbox/eventing-gitlab/releases) | ![Releasability](https://github.com/knative-sandbox/eventing-gitlab/workflows/Releasability/badge.svg) | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-gitlab-nightly-release) |
 
 Lastly:
 
-- [knative-sandbox/eventing-autoscaler-keda](https://github.com/knative-sandbox/eventing-autoscaler-keda)
+| Repo                                                                                                | Release                                                                                                                                                                                 | Releasability                                                                                                   | Nightly                                                                                                         |
+| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
+| [knative.dev/eventing-autoscaler-keda](https://github.com/knative-sandbox/eventing-autoscaler-keda) | [![Releases](https://img.shields.io/github/release-pre/knative-sandbox/eventing-autoscaler-keda.svg?sort=semver)](https://github.com/knative-sandbox/eventing-autoscaler-keda/releases) | ![Releasability](https://github.com/knative-sandbox/eventing-autoscaler-keda/workflows/Releasability/badge.svg) | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-sandbox-eventing-autoscaler-keda-nightly-release) |
 
 We have a few repos inside of Knative that are not handled in the standard
 process at the moment. They might have additional dependencies or depend on the
 releases existing. **Skip these**. Special cases are:
 
-- [knative/client](https://github.com/knative/client)
-- [knative/docs](https://github.com/knative/docs)
-- [knative/website](https://github.com/knative/website)
-- [knative/operator](https://github.com/knative/operator)
+| Repo                                                        | Release                                                                                                                                 | Releasability                                                                           | Nightly                                                                               |
+| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
+| [knative.dev/client](https://github.com/knative/client)     | [![Releases](https://img.shields.io/github/release-pre/knative/client.svg?sort=semver)](https://github.com/knative/client/releases)     | ![Releasability](https://github.com/knative/client/workflows/Releasability/badge.svg)   | ![Nightly](https://prow.knative.dev/badge.svg?jobs=ci-knative-client-nightly-release) |
+| [knative.dev/docs](https://github.com/knative/docs)         | [![Releases](https://img.shields.io/github/release-pre/knative/docs.svg?sort=semver)](https://github.com/knative/docs/releases)         | ![Releasability](https://github.com/knative/docs/workflows/Releasability/badge.svg)     | N/A                                                                                   |
+| [knative.dev/operator](https://github.com/knative/operator) | [![Releases](https://img.shields.io/github/release-pre/knative/operator.svg?sort=semver)](https://github.com/knative/operator/releases) | ![Releasability](https://github.com/knative/operator/workflows/Releasability/badge.svg) | N/A                                                                                   |
+| [knative.dev/website](https://github.com/knative/website)   | N/A                                                                                                                                     | N/A                                                                                     | N/A                                                                                   |
 
 ## After the release
 
 Send a PR like [this one](https://github.com/knative/community/pull/209) to
 grant ACLs for the next release leads, and to remove yourself from the rotation.
 Include the next release leads in the PR as a reminder.
+
+Send a PR like [this one](https://github.com/knative-sandbox/knobots/pull/18) to
+bump knobots auto release workflow to the next release.
diff --git a/controller/controller.go b/controller/controller.go
index 27fe75e40..2a28497fa 100644
--- a/controller/controller.go
+++ b/controller/controller.go
@@ -152,6 +152,13 @@ func FilterControllerGK(gk schema.GroupKind) func(obj interface{}) bool {
 	}
 }
 
+// FilterController makes it simple to create FilterFunc's for use with
+// cache.FilteringResourceEventHandler that filter based on the
+// controlling resource.
+func FilterController(r kmeta.OwnerRefable) func(obj interface{}) bool {
+	return FilterControllerGK(r.GetGroupVersionKind().GroupKind())
+}
+
 // FilterWithName makes it simple to create FilterFunc's for use with
 // cache.FilteringResourceEventHandler that filter based on a name.
 func FilterWithName(name string) func(obj interface{}) bool {
diff --git a/controller/stats_reporter.go b/controller/stats_reporter.go
index 92a5848a1..474bab3fc 100644
--- a/controller/stats_reporter.go
+++ b/controller/stats_reporter.go
@@ -26,7 +26,6 @@ import (
 	"go.opencensus.io/tag"
 	"go.uber.org/zap"
 	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/client-go/tools/cache"
 	kubemetrics "k8s.io/client-go/tools/metrics"
 	"k8s.io/client-go/util/workqueue"
 	"knative.dev/pkg/metrics"
@@ -34,8 +33,8 @@ import (
 )
 
 var (
-	workQueueDepthStat   = stats.Int64("work_queue_depth", "Depth of the work queue", stats.UnitNone)
-	reconcileCountStat   = stats.Int64("reconcile_count", "Number of reconcile operations", stats.UnitNone)
+	workQueueDepthStat   = stats.Int64("work_queue_depth", "Depth of the work queue", stats.UnitDimensionless)
+	reconcileCountStat   = stats.Int64("reconcile_count", "Number of reconcile operations", stats.UnitDimensionless)
 	reconcileLatencyStat = stats.Int64("reconcile_latency", "Latency of reconcile operations", stats.UnitMilliseconds)
 
 	// reconcileDistribution defines the bucket boundaries for the histogram of reconcile latency metric.
@@ -58,104 +57,51 @@ func init() {
 		Adds: stats.Int64(
 			"workqueue_adds_total",
 			"Total number of adds handled by workqueue",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		Depth: stats.Int64(
 			"workqueue_depth",
 			"Current depth of workqueue",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		Latency: stats.Float64(
 			"workqueue_queue_latency_seconds",
 			"How long in seconds an item stays in workqueue before being requested.",
-			"s",
+			stats.UnitSeconds,
 		),
 		Retries: stats.Int64(
 			"workqueue_retries_total",
 			"Total number of retries handled by workqueue",
-			"s",
+			stats.UnitDimensionless,
 		),
 		WorkDuration: stats.Float64(
 			"workqueue_work_duration_seconds",
 			"How long in seconds processing an item from workqueue takes.",
-			"s",
+			stats.UnitSeconds,
 		),
 		UnfinishedWorkSeconds: stats.Float64(
 			"workqueue_unfinished_work_seconds",
 			"How long in seconds the outstanding workqueue items have been in flight (total).",
-			"s",
+			stats.UnitSeconds,
 		),
 		LongestRunningProcessorSeconds: stats.Float64(
 			"workqueue_longest_running_processor_seconds",
 			"How long in seconds the longest outstanding workqueue item has been in flight.",
-			"s",
+			stats.UnitSeconds,
 		),
 	}
 	workqueue.SetProvider(wp)
 
-	// Register to receive metrics from kubernetes reflectors (what powers informers)
-	// NOTE: today these don't actually seem to wire up to anything in Kubernetes.
-	rp := &metrics.ReflectorProvider{
-		ItemsInList: stats.Float64(
-			"reflector_items_in_list",
-			"How many items an API list returns to the reflectors",
-			stats.UnitNone,
-		),
-		// TODO(mattmoor): This is not in the latest version, so it will
-		// be removed in a future version.
-		ItemsInMatch: stats.Float64(
-			"reflector_items_in_match",
-			"",
-			stats.UnitNone,
-		),
-		ItemsInWatch: stats.Float64(
-			"reflector_items_in_watch",
-			"How many items an API watch returns to the reflectors",
-			stats.UnitNone,
-		),
-		LastResourceVersion: stats.Float64(
-			"reflector_last_resource_version",
-			"Last resource version seen for the reflectors",
-			stats.UnitNone,
-		),
-		ListDuration: stats.Float64(
-			"reflector_list_duration_seconds",
-			"How long an API list takes to return and decode for the reflectors",
-			stats.UnitNone,
-		),
-		Lists: stats.Int64(
-			"reflector_lists_total",
-			"Total number of API lists done by the reflectors",
-			stats.UnitNone,
-		),
-		ShortWatches: stats.Int64(
-			"reflector_short_watches_total",
-			"Total number of short API watches done by the reflectors",
-			stats.UnitNone,
-		),
-		WatchDuration: stats.Float64(
-			"reflector_watch_duration_seconds",
-			"How long an API watch takes to return and decode for the reflectors",
-			stats.UnitNone,
-		),
-		Watches: stats.Int64(
-			"reflector_watches_total",
-			"Total number of API watches done by the reflectors",
-			stats.UnitNone,
-		),
-	}
-	cache.SetReflectorMetricsProvider(rp)
-
 	cp := &metrics.ClientProvider{
 		Latency: stats.Float64(
 			"client_latency",
 			"How long Kubernetes API requests take",
-			"s",
+			stats.UnitSeconds,
 		),
 		Result: stats.Int64(
 			"client_results",
 			"Total number of API requests (broken down by status code)",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 	}
 	opts := kubemetrics.RegisterOpts{
@@ -181,7 +127,6 @@ func init() {
 		TagKeys:     []tag.Key{reconcilerTagKey, successTagKey, NamespaceTagKey},
 	}}
 	views = append(views, wp.DefaultViews()...)
-	views = append(views, rp.DefaultViews()...)
 	views = append(views, cp.DefaultViews()...)
 
 	// Create views to see our measurements. This can return an error if
diff --git a/metrics/memstats.go b/metrics/memstats.go
index 719c7e018..d96a0f4bc 100644
--- a/metrics/memstats.go
+++ b/metrics/memstats.go
@@ -33,112 +33,112 @@ func NewMemStatsAll() *MemStatsProvider {
 		Alloc: stats.Int64(
 			"go_alloc",
 			"The number of bytes of allocated heap objects.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		TotalAlloc: stats.Int64(
 			"go_total_alloc",
 			"The cumulative bytes allocated for heap objects.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		Sys: stats.Int64(
 			"go_sys",
 			"The total bytes of memory obtained from the OS.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		Lookups: stats.Int64(
 			"go_lookups",
 			"The number of pointer lookups performed by the runtime.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		Mallocs: stats.Int64(
 			"go_mallocs",
 			"The cumulative count of heap objects allocated.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		Frees: stats.Int64(
 			"go_frees",
 			"The cumulative count of heap objects freed.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		HeapAlloc: stats.Int64(
 			"go_heap_alloc",
 			"The number of bytes of allocated heap objects.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		HeapSys: stats.Int64(
 			"go_heap_sys",
 			"The number of bytes of heap memory obtained from the OS.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		HeapIdle: stats.Int64(
 			"go_heap_idle",
 			"The number of bytes in idle (unused) spans.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		HeapInuse: stats.Int64(
 			"go_heap_in_use",
 			"The number of bytes in in-use spans.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		HeapReleased: stats.Int64(
 			"go_heap_released",
 			"The number of bytes of physical memory returned to the OS.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		HeapObjects: stats.Int64(
 			"go_heap_objects",
 			"The number of allocated heap objects.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		StackInuse: stats.Int64(
 			"go_stack_in_use",
 			"The number of bytes in stack spans.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		StackSys: stats.Int64(
 			"go_stack_sys",
 			"The number of bytes of stack memory obtained from the OS.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		MSpanInuse: stats.Int64(
 			"go_mspan_in_use",
 			"The number of bytes of allocated mspan structures.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		MSpanSys: stats.Int64(
 			"go_mspan_sys",
 			"The number of bytes of memory obtained from the OS for mspan structures.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		MCacheInuse: stats.Int64(
 			"go_mcache_in_use",
 			"The number of bytes of allocated mcache structures.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		MCacheSys: stats.Int64(
 			"go_mcache_sys",
 			"The number of bytes of memory obtained from the OS for mcache structures.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		BuckHashSys: stats.Int64(
 			"go_bucket_hash_sys",
 			"The number of bytes of memory in profiling bucket hash tables.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		GCSys: stats.Int64(
 			"go_gc_sys",
 			"The number of bytes of memory in garbage collection metadata.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		OtherSys: stats.Int64(
 			"go_other_sys",
 			"The number of bytes of memory in miscellaneous off-heap runtime allocations.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		NextGC: stats.Int64(
 			"go_next_gc",
 			"The target heap size of the next GC cycle.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		LastGC: stats.Int64(
 			"go_last_gc",
@@ -153,17 +153,17 @@ func NewMemStatsAll() *MemStatsProvider {
 		NumGC: stats.Int64(
 			"go_num_gc",
 			"The number of completed GC cycles.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		NumForcedGC: stats.Int64(
 			"go_num_forced_gc",
 			"The number of GC cycles that were forced by the application calling the GC function.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 		GCCPUFraction: stats.Float64(
 			"go_gc_cpu_fraction",
 			"The fraction of this program's available CPU time used by the GC since the program started.",
-			stats.UnitNone,
+			stats.UnitDimensionless,
 		),
 	}
 }
diff --git a/metrics/reflector.go b/metrics/reflector.go
deleted file mode 100644
index 548b811b6..000000000
--- a/metrics/reflector.go
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
-Copyright 2019 The Knative Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package metrics
-
-import (
-	"go.opencensus.io/stats"
-	"go.opencensus.io/stats/view"
-	"go.opencensus.io/tag"
-	"k8s.io/client-go/tools/cache"
-)
-
-// ReflectorProvider implements reflector.MetricsProvider and may be used with
-// reflector.SetProvider to have metrics exported to the provided metrics.
-type ReflectorProvider struct {
-	ItemsInList *stats.Float64Measure
-	// TODO(mattmoor): This is not in the latest version, so it will
-	// be removed in a future version.
-	ItemsInMatch        *stats.Float64Measure
-	ItemsInWatch        *stats.Float64Measure
-	LastResourceVersion *stats.Float64Measure
-	ListDuration        *stats.Float64Measure
-	Lists               *stats.Int64Measure
-	ShortWatches        *stats.Int64Measure
-	WatchDuration       *stats.Float64Measure
-	Watches             *stats.Int64Measure
-}
-
-var (
-	_ cache.MetricsProvider = (*ReflectorProvider)(nil)
-)
-
-// NewItemsInListMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewItemsInListMetric(name string) cache.SummaryMetric {
-	return floatMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.ItemsInList,
-	}
-}
-
-// ItemsInListView returns a view of the ItemsInList metric.
-func (rp *ReflectorProvider) ItemsInListView() *view.View {
-	return measureView(rp.ItemsInList, view.Distribution(BucketsNBy10(0.1, 6)...))
-}
-
-// NewItemsInMatchMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewItemsInMatchMetric(name string) cache.SummaryMetric {
-	return floatMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.ItemsInMatch,
-	}
-}
-
-// ItemsInMatchView returns a view of the ItemsInMatch metric.
-func (rp *ReflectorProvider) ItemsInMatchView() *view.View {
-	return measureView(rp.ItemsInMatch, view.Distribution(BucketsNBy10(0.1, 6)...))
-}
-
-// NewItemsInWatchMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewItemsInWatchMetric(name string) cache.SummaryMetric {
-	return floatMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.ItemsInWatch,
-	}
-}
-
-// ItemsInWatchView returns a view of the ItemsInWatch metric.
-func (rp *ReflectorProvider) ItemsInWatchView() *view.View {
-	return measureView(rp.ItemsInWatch, view.Distribution(BucketsNBy10(0.1, 6)...))
-}
-
-// NewLastResourceVersionMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewLastResourceVersionMetric(name string) cache.GaugeMetric {
-	return floatMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.LastResourceVersion,
-	}
-}
-
-// LastResourceVersionView returns a view of the LastResourceVersion metric.
-func (rp *ReflectorProvider) LastResourceVersionView() *view.View {
-	return measureView(rp.LastResourceVersion, view.LastValue())
-}
-
-// NewListDurationMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewListDurationMetric(name string) cache.SummaryMetric {
-	return floatMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.ListDuration,
-	}
-}
-
-// ListDurationView returns a view of the ListDuration metric.
-func (rp *ReflectorProvider) ListDurationView() *view.View {
-	return measureView(rp.ListDuration, view.Distribution(BucketsNBy10(0.1, 6)...))
-}
-
-// NewListsMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewListsMetric(name string) cache.CounterMetric {
-	return counterMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.Lists,
-	}
-}
-
-// ListsView returns a view of the Lists metric.
-func (rp *ReflectorProvider) ListsView() *view.View {
-	return measureView(rp.Lists, view.Count())
-}
-
-// NewShortWatchesMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewShortWatchesMetric(name string) cache.CounterMetric {
-	return counterMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.ShortWatches,
-	}
-}
-
-// ShortWatchesView returns a view of the ShortWatches metric.
-func (rp *ReflectorProvider) ShortWatchesView() *view.View {
-	return measureView(rp.ShortWatches, view.Count())
-}
-
-// NewWatchDurationMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewWatchDurationMetric(name string) cache.SummaryMetric {
-	return floatMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.WatchDuration,
-	}
-}
-
-// WatchDurationView returns a view of the WatchDuration metric.
-func (rp *ReflectorProvider) WatchDurationView() *view.View {
-	return measureView(rp.WatchDuration, view.Distribution(BucketsNBy10(0.1, 6)...))
-}
-
-// NewWatchesMetric implements MetricsProvider
-func (rp *ReflectorProvider) NewWatchesMetric(name string) cache.CounterMetric {
-	return counterMetric{
-		mutators: []tag.Mutator{tag.Insert(tagName, name)},
-		measure:  rp.Watches,
-	}
-}
-
-// WatchesView returns a view of the Watches metric.
-func (rp *ReflectorProvider) WatchesView() *view.View {
-	return measureView(rp.Watches, view.Count())
-}
-
-// DefaultViews returns a list of views suitable for passing to view.Register
-func (rp *ReflectorProvider) DefaultViews() []*view.View {
-	return []*view.View{
-		rp.ItemsInListView(),
-		rp.ItemsInMatchView(),
-		rp.ItemsInWatchView(),
-		rp.LastResourceVersionView(),
-		rp.ListDurationView(),
-		rp.ListsView(),
-		rp.ShortWatchesView(),
-		rp.WatchDurationView(),
-		rp.WatchesView(),
-	}
-}
diff --git a/metrics/resource_view.go b/metrics/resource_view.go
index 7135af70a..236fd588b 100644
--- a/metrics/resource_view.go
+++ b/metrics/resource_view.go
@@ -82,10 +82,16 @@ func cleanup() {
 	expiryCutoff := allMeters.clock.Now().Add(-1 * maxMeterExporterAge)
 	allMeters.lock.Lock()
 	defer allMeters.lock.Unlock()
+	resourceViews.lock.Lock()
+	defer resourceViews.lock.Unlock()
 	for key, meter := range allMeters.meters {
 		if key != "" && meter.t.Before(expiryCutoff) {
 			flushGivenExporter(meter.e)
+			// Make a copy of views to avoid data races
+			viewsCopy := copyViews(resourceViews.views)
+			meter.m.Unregister(viewsCopy...)
 			delete(allMeters.meters, key)
+			meter.m.Stop()
 		}
 	}
 }
@@ -139,7 +145,7 @@ func RegisterResourceView(views ...*view.View) error {
 	return nil
 }
 
-// UnregisterResourceView is similar to view.Unregiste(), except that it will
+// UnregisterResourceView is similar to view.Unregister(), except that it will
 // unregister the view across all Resources tracked byt he system, rather than
 // simply the default view.
 func UnregisterResourceView(views ...*view.View) {
diff --git a/network/network.go b/network/network.go
index b2ac63ce7..ee5ce7c48 100644
--- a/network/network.go
+++ b/network/network.go
@@ -52,18 +52,20 @@ const (
 	// uses to find out which version of the networking config is deployed.
 	HashHeaderName = "K-Network-Hash"
 
+	// KubeProbeUAPrefix is the prefix for the User-Agent header.
 	// Since K8s 1.8, prober requests have
 	//   User-Agent = "kube-probe/{major-version}.{minor-version}".
 	KubeProbeUAPrefix = "kube-probe/"
 
+	// KubeletProbeHeaderName is the header name to augment the probes, because
 	// Istio with mTLS rewrites probes, but their probes pass a different
-	// user-agent.  So we augment the probes with this header.
+	// user-agent.
 	KubeletProbeHeaderName = "K-Kubelet-Probe"
 )
 
 // IsKubeletProbe returns true if the request is a Kubernetes probe.
 func IsKubeletProbe(r *http.Request) bool {
-	return strings.HasPrefix(r.Header.Get("User-Agent"), KubeProbeUAPrefix) ||
+	return strings.HasPrefix(r.Header.Get(UserAgentKey), KubeProbeUAPrefix) ||
 		r.Header.Get(KubeletProbeHeaderName) != ""
 }
 
diff --git a/source/source_stats_reporter.go b/source/source_stats_reporter.go
index b6d1ca93b..f343d9d75 100644
--- a/source/source_stats_reporter.go
+++ b/source/source_stats_reporter.go
@@ -35,6 +35,12 @@ var (
 		stats.UnitDimensionless,
 	)
 
+	// retryEventCountM is a counter which records the number of events sent by the source in retries.
+	retryEventCountM = stats.Int64(
+		"retry_event_count",
+		"Number of retry events sent",
+		stats.UnitDimensionless,
+	)
 	// Create the tag keys that will be used to add tags to our measurements.
 	// Tag keys must conform to the restrictions described in
 	// go.opencensus.io/tag/validate.go. Currently those restrictions are:
@@ -51,6 +57,7 @@ var (
 	responseTimeout        = tag.MustNewKey(metricskey.LabelResponseTimeout)
 )
 
+// ReportArgs defines the arguments for reporting metrics.
 type ReportArgs struct {
 	Namespace     string
 	EventType     string
@@ -69,6 +76,7 @@ func init() {
 type StatsReporter interface {
 	// ReportEventCount captures the event count. It records one per call.
 	ReportEventCount(args *ReportArgs, responseCode int) error
+	ReportRetryEventCount(args *ReportArgs, responseCode int) error
 }
 
 var _ StatsReporter = (*reporter)(nil)
@@ -98,6 +106,15 @@ func (r *reporter) ReportEventCount(args *ReportArgs, responseCode int) error {
 	return nil
 }
 
+func (r *reporter) ReportRetryEventCount(args *ReportArgs, responseCode int) error {
+	ctx, err := r.generateTag(args, responseCode)
+	if err != nil {
+		return err
+	}
+	metrics.Record(ctx, retryEventCountM.M(1))
+	return nil
+}
+
 func (r *reporter) generateTag(args *ReportArgs, responseCode int) (context.Context, error) {
 	return tag.New(
 		r.ctx,
@@ -132,6 +149,12 @@ func register() {
 			Aggregation: view.Count(),
 			TagKeys:     tagKeys,
 		},
+		&view.View{
+			Description: retryEventCountM.Description(),
+			Measure:     retryEventCountM,
+			Aggregation: view.Count(),
+			TagKeys:     tagKeys,
+		},
 	); err != nil {
 		panic(err)
 	}
diff --git a/system/clock.go b/system/clock.go
deleted file mode 100644
index 7d99d9b5c..000000000
--- a/system/clock.go
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-Copyright 2019 The Knative Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package system
-
-import (
-	"time"
-)
-
-// Mockable interface for time based testing
-type Clock interface {
-	Now() time.Time
-}
-
-type RealClock struct{}
-
-func (RealClock) Now() time.Time {
-	return time.Now()
-}


Test patch:
diff --git a/metrics/config_test.go b/metrics/config_test.go
index 890f27ddb..735e8865d 100644
--- a/metrics/config_test.go
+++ b/metrics/config_test.go
@@ -1048,8 +1048,8 @@ func TestStackdriverRecord(t *testing.T) {
 		},
 	}
 
-	servedCount := stats.Int64("request_count", "Number of requests", stats.UnitNone)
-	statCount := stats.Int64("stat_errors", "Number of errors calling stat", stats.UnitNone)
+	servedCount := stats.Int64("request_count", "Number of requests", stats.UnitDimensionless)
+	statCount := stats.Int64("stat_errors", "Number of errors calling stat", stats.UnitDimensionless)
 	emptyTags := map[string]string{}
 
 	for name, data := range testCases {
diff --git a/metrics/record_test.go b/metrics/record_test.go
index fe02ea13a..e597926ef 100644
--- a/metrics/record_test.go
+++ b/metrics/record_test.go
@@ -39,7 +39,7 @@ type cases struct {
 }
 
 func TestRecordServing(t *testing.T) {
-	measure := stats.Int64("request_count", "Number of reconcile operations", stats.UnitNone)
+	measure := stats.Int64("request_count", "Number of reconcile operations", stats.UnitDimensionless)
 	// Increase the measurement value for each test case so that checking
 	// the last value ensures the measurement has been recorded.
 	shouldReportCases := []cases{{
@@ -65,7 +65,7 @@ func TestRecordServing(t *testing.T) {
 }
 
 func TestRecordEventing(t *testing.T) {
-	measure := stats.Int64("event_count", "Number of event received", stats.UnitNone)
+	measure := stats.Int64("event_count", "Number of event received", stats.UnitDimensionless)
 	// Increase the measurement value for each test case so that checking
 	// the last value ensures the measurement has been recorded.
 	shouldReportCases := []cases{{
@@ -92,8 +92,8 @@ func TestRecordEventing(t *testing.T) {
 
 func TestRecordBatch(t *testing.T) {
 	ctx := context.Background()
-	measure1 := stats.Int64("count1", "First counter", stats.UnitNone)
-	measure2 := stats.Int64("count2", "Second counter", stats.UnitNone)
+	measure1 := stats.Int64("count1", "First counter", stats.UnitDimensionless)
+	measure2 := stats.Int64("count2", "Second counter", stats.UnitDimensionless)
 	v := []*view.View{{
 		Measure:     measure1,
 		Aggregation: view.LastValue(),
@@ -194,7 +194,7 @@ func TestBucketsNBy10(t *testing.T) {
 }
 
 func TestMeter(t *testing.T) {
-	measure := stats.Int64("request_count", "Number of reconcile operations", stats.UnitNone)
+	measure := stats.Int64("request_count", "Number of reconcile operations", stats.UnitDimensionless)
 	// Increase the measurement value for each test case so that checking
 	// the last value ensures the measurement has been recorded.
 	meterTestCases := []cases{{
diff --git a/metrics/reflector_test.go b/metrics/reflector_test.go
deleted file mode 100644
index 132886b12..000000000
--- a/metrics/reflector_test.go
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-Copyright 2019 The Knative Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package metrics
-
-import (
-	"testing"
-
-	"go.opencensus.io/stats/view"
-	kubeinformers "k8s.io/client-go/informers"
-	kubefake "k8s.io/client-go/kubernetes/fake"
-	"k8s.io/client-go/tools/cache"
-
-	"knative.dev/pkg/metrics/metricstest"
-)
-
-func TestReflectorMetrics(t *testing.T) {
-	rp := &ReflectorProvider{
-		ItemsInList:         newFloat64("items_in_list"),
-		ItemsInMatch:        newFloat64("items_in_match"),
-		ItemsInWatch:        newFloat64("items_in_watch"),
-		LastResourceVersion: newFloat64("last_resource_version"),
-		ListDuration:        newFloat64("list_duration"),
-		Lists:               newInt64("lists"),
-		ShortWatches:        newInt64("short_watches"),
-		WatchDuration:       newFloat64("watch_duration"),
-		Watches:             newInt64("watches"),
-	}
-	cache.SetReflectorMetricsProvider(rp)
-
-	// Reset the metrics configuration to avoid leaked state from other tests.
-	setCurMetricsConfig(nil)
-
-	views := rp.DefaultViews()
-	if got, want := len(views), 9; got != want {
-		t.Errorf("len(DefaultViews()) = %d, want %d", got, want)
-	}
-	if err := view.Register(views...); err != nil {
-		t.Error("view.Register() =", err)
-	}
-	defer view.Unregister(views...)
-
-	metricstest.CheckStatsNotReported(t, "items_in_list", "items_in_match", "items_in_watch",
-		"last_resource_version", "list_duration", "lists", "short_watches", "watch_duration", "watches")
-
-	stopCh := make(chan struct{})
-	defer close(stopCh)
-
-	fake := kubefake.NewSimpleClientset()
-	factory := kubeinformers.NewSharedInformerFactory(fake, 0)
-	endpoints := factory.Core().V1().Endpoints()
-
-	informer := endpoints.Informer()
-	go informer.Run(stopCh)
-
-	if ok := cache.WaitForCacheSync(stopCh, informer.HasSynced); !ok {
-		t.Error("failed to wait for endpoints cache to sync")
-	}
-
-	// TODO(mattmoor): The reflector metrics don't seem to be hooked up to anything,
-	// so nothing is reported...  (－‸ლ)
-	metricstest.CheckStatsNotReported(t, "items_in_list", "items_in_match", "items_in_watch",
-		"last_resource_version", "list_duration", "lists", "short_watches", "watch_duration", "watches")
-}
diff --git a/metrics/resource_view_test.go b/metrics/resource_view_test.go
index 8814447aa..37766239a 100644
--- a/metrics/resource_view_test.go
+++ b/metrics/resource_view_test.go
@@ -25,6 +25,7 @@ import (
 	"go.opencensus.io/stats"
 	"go.opencensus.io/stats/view"
 	"k8s.io/apimachinery/pkg/util/clock"
+	"k8s.io/apimachinery/pkg/util/wait"
 )
 
 var (
@@ -74,6 +75,8 @@ type testExporter struct {
 	id string
 }
 
+func (testExporter) ExportView(viewData *view.Data) {}
+
 func TestSetFactory(t *testing.T) {
 	var oldFactory ResourceExporterFactory
 	func() {
@@ -170,7 +173,13 @@ func TestAllMetersExpiration(t *testing.T) {
 
 	// Expire the second entry
 	fakeClock.Step(9 * time.Minute) // t+12m
-	time.Sleep(time.Second)         // Wait a second on the wallclock, so that the cleanup thread has time to finish a loop
+	_ = wait.PollImmediate(100*time.Millisecond, 5*time.Second, func() (bool, error) {
+		// Non-expiring defaultMeter should be available along with the non-expired entry
+		allMeters.lock.Lock()
+		defer allMeters.lock.Unlock()
+		return len(allMeters.meters) == 2, nil
+	})
+
 	allMeters.lock.Lock()
 	if len(allMeters.meters) != 2 {
 		t.Errorf("len(allMeters)=%d, want: 2", len(allMeters.meters))
@@ -189,6 +198,68 @@ func TestAllMetersExpiration(t *testing.T) {
 	// (123=9m, 456=evicted, 789=0m)
 }
 
+func TestIfAllMeterResourcesAreRemoved(t *testing.T) {
+	allMeters.clock = clock.Clock(clock.NewFakeClock(time.Now()))
+	var fakeClock *clock.FakeClock = allMeters.clock.(*clock.FakeClock)
+	ClearMetersForTest() // t+0m
+	// Register many resources at once
+	for i := 1; i <= 100; i++ {
+		res := resource.Resource{Labels: map[string]string{"foo": "bar"}}
+		res.Labels["id"] = fmt.Sprint(i)
+		if _, err := optionForResource(&res); err != nil {
+			t.Error("Should succeed getting option, instead got error ", err)
+		}
+		m := stats.Int64("testView_sum", "", stats.UnitDimensionless)
+		v := view.View{Name: fmt.Sprintf("testview-%d", i), Measure: m, Aggregation: view.Sum()}
+
+		err := RegisterResourceView(&v)
+		if err != nil {
+			t.Fatal("RegisterResourceView =", err)
+		}
+	}
+
+	func() {
+		allMeters.lock.Lock()
+		resourceViews.lock.Lock()
+		defer allMeters.lock.Unlock()
+		defer resourceViews.lock.Unlock()
+		// Make a copy to test against as allMeters should be cleaned up
+		copyAllMeters := make(map[string]*meterExporter, len(allMeters.meters))
+		for k, v := range allMeters.meters {
+			copyAllMeters[k] = v
+		}
+
+		for _, meter := range copyAllMeters {
+			for _, mView := range resourceViews.views {
+				want, got := mView, meter.m.Find(mView.Name)
+				if got == nil {
+					t.Errorf("View %s is not available", want.Name)
+				} else if want.Name != got.Name {
+					t.Errorf("Want %v, got %v", want.Name, got.Name)
+				}
+			}
+		}
+	}()
+
+	// Expire all meters and views
+	// We need to unlock before we move the clock ahead in time
+	fakeClock.Step(12 * time.Minute) // t+12m
+	_ = wait.PollImmediate(100*time.Millisecond, 5*time.Second, func() (bool, error) {
+		// Non-expiring defaultMeter should be available
+		allMeters.lock.Lock()
+		defer allMeters.lock.Unlock()
+		return len(allMeters.meters) == 1, nil
+	})
+
+	allMeters.lock.Lock()
+	defer allMeters.lock.Unlock()
+	resourceViews.lock.Lock()
+	defer resourceViews.lock.Unlock()
+	if len(allMeters.meters) != 1 {
+		t.Errorf("len(allMeters)=%d, want: 1", len(allMeters.meters))
+	}
+}
+
 func TestResourceAsString(t *testing.T) {
 	r1 := &resource.Resource{Type: "foobar", Labels: map[string]string{"k1": "v1", "k3": "v3", "k2": "v2"}}
 	r2 := &resource.Resource{Type: "foobar", Labels: map[string]string{"k2": "v2", "k3": "v3", "k1": "v1"}}
diff --git a/network/handlers/drain_test.go b/network/handlers/drain_test.go
index 43b6bd15e..0cfcdb510 100644
--- a/network/handlers/drain_test.go
+++ b/network/handlers/drain_test.go
@@ -70,7 +70,7 @@ func TestDrainMechanics(t *testing.T) {
 		req   = &http.Request{}
 		probe = &http.Request{
 			Header: http.Header{
-				"User-Agent": []string{network.KubeProbeUAPrefix},
+				network.UserAgentKey: []string{network.KubeProbeUAPrefix},
 			},
 		}
 		cnt   = 0
@@ -328,7 +328,7 @@ func TestHealthCheck(t *testing.T) {
 				Path: "/healthz",
 			},
 			Header: http.Header{
-				"User-Agent": []string{network.KubeProbeUAPrefix},
+				network.UserAgentKey: []string{network.KubeProbeUAPrefix},
 			},
 		}
 		cnt     = 0
diff --git a/network/network_test.go b/network/network_test.go
index ec3903e36..3ed1cd9d2 100644
--- a/network/network_test.go
+++ b/network/network_test.go
@@ -30,11 +30,11 @@ func TestIsKubeletProbe(t *testing.T) {
 	if IsKubeletProbe(req) {
 		t.Error("Not a kubelet probe but counted as such")
 	}
-	req.Header.Set("User-Agent", KubeProbeUAPrefix+"1.14")
+	req.Header.Set(UserAgentKey, KubeProbeUAPrefix+"1.14")
 	if !IsKubeletProbe(req) {
 		t.Error("kubelet probe but not counted as such")
 	}
-	req.Header.Del("User-Agent")
+	req.Header.Del(UserAgentKey)
 	if IsKubeletProbe(req) {
 		t.Error("Not a kubelet probe but counted as such")
 	}
diff --git a/reconciler/testing/clock.go b/reconciler/testing/clock.go
deleted file mode 100644
index 44ba77cdb..000000000
--- a/reconciler/testing/clock.go
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-Copyright 2019 The Knative Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package testing
-
-import (
-	"time"
-)
-
-type FakeClock struct {
-	Time time.Time
-}
-
-func (c FakeClock) Now() time.Time {
-	return c.Time
-}
diff --git a/source/source_stats_reporter_test.go b/source/source_stats_reporter_test.go
index 4c7dedc24..bfeeb4918 100644
--- a/source/source_stats_reporter_test.go
+++ b/source/source_stats_reporter_test.go
@@ -51,14 +51,31 @@ func TestStatsReporter(t *testing.T) {
 		metricskey.LabelResponseCodeClass: "2xx",
 	}
 
-	// test ReportEventCount
+	retryWantTags := map[string]string{
+		metricskey.LabelNamespaceName:     "testns",
+		metricskey.LabelEventType:         "dev.knative.event",
+		metricskey.LabelEventSource:       "unit-test",
+		metricskey.LabelName:              "testsource",
+		metricskey.LabelResourceGroup:     "testresourcegroup",
+		metricskey.LabelResponseCode:      "503",
+		metricskey.LabelResponseCodeClass: "5xx",
+	}
+
+	// test ReportEventCount and ReportRetryEventCount
 	expectSuccess(t, func() error {
 		return r.ReportEventCount(args, http.StatusAccepted)
 	})
 	expectSuccess(t, func() error {
 		return r.ReportEventCount(args, http.StatusAccepted)
 	})
+	expectSuccess(t, func() error {
+		return r.ReportRetryEventCount(args, http.StatusServiceUnavailable)
+	})
+	expectSuccess(t, func() error {
+		return r.ReportRetryEventCount(args, http.StatusServiceUnavailable)
+	})
 	metricstest.CheckCountData(t, "event_count", wantTags, 2)
+	metricstest.CheckCountData(t, "retry_event_count", retryWantTags, 2)
 }
 
 func expectSuccess(t *testing.T, f func() error) {
@@ -75,5 +92,6 @@ func setup() {
 func resetMetrics() {
 	// OpenCensus metrics carry global state that need to be reset between unit tests.
 	metricstest.Unregister("event_count")
+	metricstest.Unregister("retry_event_count")
 	register()
 }