Repository: knative/serving
Pull request #10250 (2020-12-03 01:55:38)

Add Yanwei as autoscaling approver
Yanwei has been a contributor to Knative from the very beginning, with
first PR going in February 2018. He contributed to various pieces of
autoscaling code including metrics, scraping and autoscaler scaleout.

- Contributor over 3 mo: ✅
- Primary reviewer for at least 10 substantial PRs to the codebase: ✅
(30 L:
https://github.com/knative/serving/pulls?q=is%3Apr+reviewed-by%3Ayanweiguo+is%3Aclosed++label%3Aarea%2Fautoscale+++-author%3Ayanweiguo+label%3Asize%2FL+ and some XL and XXL code reviews)
- Reviewed at least 30 PRs to the codebase: ✅ (77
https://github.com/knative/serving/pulls?q=is%3Apr+reviewed-by%3Ayanweiguo+is%3Aclosed++label%3Aarea%2Fautoscale+++-author%3Ayanweiguo+)
* Also 43 contributed merged PRs.
* Nominated by an a WG lead: vagababov.



Also sort the file :)

/assign @markusthoemmes  — for second Autoscaling and TOC approval
/assign @mattmoor @evankanderson @tcnghia @grantr as TOC
 

knative-prow-robot: @vagababov: GitHub didn't allow me to assign the following users: TOC, as.

Note that only [knative members](https://github.com/orgs/knative/people), repo collaborators and people who have commented on this issue/PR can be assigned. Additionally, issues/PRs can only have 10 assignees at the same time.
For more information please see [the contributor guide](https://git.k8s.io/community/contributors/guide/first-contribution.md#issue-assignment-in-github)

<details>

In response to [this](https://github.com/knative/serving/pull/10250):

>Yanwei has been a contributor to Knative from the very beginning, with
>first PR going in February 2018. He contributed to various pieces of
>autoscaling code including metrics, scraping and autoscaler scaleout.
>
>- Contributor over 3 mo: ✅
>- Primary reviewer for at least 10 substantial PRs to the codebase: ✅
>(30 L:
>https://github.com/knative/serving/pulls?q=is%3Apr+reviewed-by%3Ayanweiguo+is%3Aclosed++label%3Aarea%2Fautoscale+++-author%3Ayanweiguo+label%3Asize%2FL+ and some XL and XXL code reviews)
>- Reviewed at least 30 PRs to the codebase: ✅ (77
>https://github.com/knative/serving/pulls?q=is%3Apr+reviewed-by%3Ayanweiguo+is%3Aclosed++label%3Aarea%2Fautoscale+++-author%3Ayanweiguo+)
>* Also 43 contributed merged PRs.
>* Nominated by an a WG lead: vagababov.
>
>
>
>Also sort the file :)
>
>/assign @markusthoemmes  — for second and TOC approval
>/assign @mattmoor @evankanderson @tcnghia @grantr as TOC
> 


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/serving/pull/10250#" title="Author self-approved">vagababov</a>*

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

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

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

- ~~[OWNERS](https://github.com/knative/serving/blob/master/OWNERS)~~ [vagababov]

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":[]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative/serving/pull/10250?src=pr&el=h1) Report
> Merging [#10250](https://codecov.io/gh/knative/serving/pull/10250?src=pr&el=desc) (315a66a) into [master](https://codecov.io/gh/knative/serving/commit/8813e5c35cd6c5ce9c01b8d0636df97935557b93?el=desc) (8813e5c) will **decrease** coverage by `0.02%`.
> The diff coverage is `n/a`.

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

```diff
@@            Coverage Diff             @@
##           master   #10250      +/-   ##
==========================================
- Coverage   88.11%   88.09%   -0.03%     
==========================================
  Files         184      184              
  Lines        8619     8619              
==========================================
- Hits         7595     7593       -2     
- Misses        787      789       +2     
  Partials      237      237              
```


| [Impacted Files](https://codecov.io/gh/knative/serving/pull/10250?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pkg/activator/net/revision\_backends.go](https://codecov.io/gh/knative/serving/pull/10250/diff?src=pr&el=tree#diff-cGtnL2FjdGl2YXRvci9uZXQvcmV2aXNpb25fYmFja2VuZHMuZ28=) | `90.49% <0.00%> (-0.91%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative/serving/pull/10250?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/serving/pull/10250?src=pr&el=footer). Last update [8813e5c...315a66a](https://codecov.io/gh/knative/serving/pull/10250?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 f13cc479a..ca0820a6e 100644
--- a/.github/workflows/knative-releasability.yaml
+++ b/.github/workflows/knative-releasability.yaml
@@ -142,7 +142,7 @@ jobs:
           echo 'SLACK_TITLE=Releasability for ${{ github.repository }} @ ${{ env.RELEASE }} is NO-GO!' >> $GITHUB_ENV
 
       - name: Post status to Slack
-        if: steps.exists.outputs.release-branch == 'false'
+        if: ${{ secrets.SLACK_WEBHOOK != '' && steps.exists.outputs.release-branch == 'false' }}
         uses: rtCamp/action-slack-notify@v2.1.0
         env:
           SLACK_ICON: http://github.com/knative.png?size=48
diff --git a/.github/workflows/knative-style.yaml b/.github/workflows/knative-style.yaml
index 56360215f..5d3d3163e 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.1.15
+          WOKE_VERSION: v0.4.1
         run: |
           TEMP_PATH="$(mktemp -d)"
           cd $TEMP_PATH
diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES
index 5ac75d31a..c4dec9529 100644
--- a/OWNERS_ALIASES
+++ b/OWNERS_ALIASES
@@ -24,7 +24,6 @@ aliases:
   - dprotaso        # API
   - markusthoemmes  # Scaling
   - mattmoor        # API
-  - mdemirhan       # Network
   - tcnghia         # Network
   - vagababov       # Scaling
 
@@ -35,21 +34,19 @@ aliases:
   - grantr          # TOC
   - markusthoemmes  # Scaling/TOC
   - mattmoor        # API/TOC
-  - mdemirhan       # Network
   - nak3            # Network
   - tcnghia         # Network/TOC
   - ZhiminXiang     # Network
   - vagababov       # Scaling
 
   autoscaling-approvers:
+  - julz
   - markusthoemmes
-  - mdemirhan
   - vagababov
-  - julz
+  - yanweiguo
   autoscaling-reviewers:
   - julz
   - markusthoemmes
-  - mdemirhan
   - taragu
   - vagababov
   - yanweiguo
@@ -74,7 +71,6 @@ aliases:
   networking-approvers:
   - JRBANCEL
   - markusthoemmes
-  - mdemirhan
   - nak3
   - tcnghia
   - vagababov
@@ -83,7 +79,6 @@ aliases:
   - andrew-su
   - JRBANCEL
   - markusthoemmes
-  - mdemirhan
   - nak3
   - shashwathi
   - tcnghia
diff --git a/config/core/configmaps/logging.yaml b/config/core/configmaps/logging.yaml
index c6acaa972..b8d95c0de 100644
--- a/config/core/configmaps/logging.yaml
+++ b/config/core/configmaps/logging.yaml
@@ -20,7 +20,7 @@ metadata:
   labels:
     serving.knative.dev/release: devel
   annotations:
-    knative.dev/example-checksum: "23eed3d8"
+    knative.dev/example-checksum: "56c59cba"
 data:
   _example: |
     ################################
@@ -47,11 +47,11 @@ data:
         "errorOutputPaths": ["stderr"],
         "encoding": "json",
         "encoderConfig": {
-          "timeKey": "ts",
-          "levelKey": "level",
+          "timeKey": "timestamp",
+          "levelKey": "severity",
           "nameKey": "logger",
           "callerKey": "caller",
-          "messageKey": "msg",
+          "messageKey": "message",
           "stacktraceKey": "stacktrace",
           "lineEnding": "",
           "levelEncoder": "",
diff --git a/go.mod b/go.mod
index b823081e6..71819088c 100644
--- a/go.mod
+++ b/go.mod
@@ -34,8 +34,8 @@ require (
 	k8s.io/client-go v0.18.12
 	k8s.io/code-generator v0.18.12
 	k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29
-	knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6
+	knative.dev/caching v0.0.0-20201204024709-8decac65dea7
 	knative.dev/hack v0.0.0-20201201234937-fddbf732e450
-	knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7
-	knative.dev/pkg v0.0.0-20201130192436-e5346d90e980
+	knative.dev/networking v0.0.0-20201203234509-4cd0793eed11
+	knative.dev/pkg v0.0.0-20201204175509-c9bac6be76ca
 )
diff --git a/go.sum b/go.sum
index 6d21f16db..ac9251412 100644
--- a/go.sum
+++ b/go.sum
@@ -134,6 +134,8 @@ github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17
 github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
 github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
+github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE=
+github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc=
 github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE=
 github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q=
 github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
@@ -1214,18 +1216,16 @@ k8s.io/legacy-cloud-providers v0.18.8/go.mod h1:tgp4xYf6lvjrWnjQwTOPvWQE9IVqSBGP
 k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
 k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE=
 k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6 h1:W1R7UnGSGJmL6btl8AY8AVCT2cEwgHzRtlort7icB5M=
-knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6/go.mod h1:IocU4F1XK8udXpTRC4m9KWyEVtT928sSP+T7Oy34UDg=
-knative.dev/hack v0.0.0-20201120192952-353db687ec5b h1:Lc+AKgwhAZUD98mN++qTHeeaP6FRmS8fcwc/rXkP8G0=
-knative.dev/hack v0.0.0-20201120192952-353db687ec5b/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
+knative.dev/caching v0.0.0-20201204024709-8decac65dea7 h1:ZGlDPyF7ycBjKZ/kBFQNAYKJORvtVo88ofk5RQVUAw4=
+knative.dev/caching v0.0.0-20201204024709-8decac65dea7/go.mod h1:addawKx4UeuW2pSFGXQPDJ8w+OZmG3MQ+rdT3jjvCxU=
 knative.dev/hack v0.0.0-20201201234937-fddbf732e450 h1:IyitWF7OzfunCgE4b9ZsJAeIRoQ6JOyqDrz/19X4iS4=
 knative.dev/hack v0.0.0-20201201234937-fddbf732e450/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7 h1:O40i4ZCYfpaw7m1yUwtmRhBOdT0HRp3MYD4PWaRzYqI=
-knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7/go.mod h1:EpImbpW3gu85Mg39GT7gUJTVYLtFYWDsZQCZlKFmGUM=
-knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a h1:pdJpLaq50mLKrPWYSQgTH2p64Dk7Fq/xID6l0F69cVY=
-knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a/go.mod h1:wXZqP8MXCxb51yNFlecA13BwG7Hk370SWDFWV4dx4ug=
-knative.dev/pkg v0.0.0-20201130192436-e5346d90e980 h1:44zakwrFjbivCM/YR+ni70e9u1ELtwA7VF1HSmUcj+g=
-knative.dev/pkg v0.0.0-20201130192436-e5346d90e980/go.mod h1:wXZqP8MXCxb51yNFlecA13BwG7Hk370SWDFWV4dx4ug=
+knative.dev/networking v0.0.0-20201203234509-4cd0793eed11 h1:sogSEftyYRTNZ3g2Ynmvw8djj9X0RwBNa9GCDDLQMr4=
+knative.dev/networking v0.0.0-20201203234509-4cd0793eed11/go.mod h1:vj8h8ODz+HnStJgIgvAY2pyc146SJA1CaB9iKFpSjiM=
+knative.dev/pkg v0.0.0-20201203193109-a536174bdf99 h1:92aXqHzL90KS8KG/8tw90cUs+nEDssZXmeux7LLfrMs=
+knative.dev/pkg v0.0.0-20201203193109-a536174bdf99/go.mod h1:Jtbz2/1gB8EZgZA4VvabTxM+AcDt2WL2P0RaFnKcOX8=
+knative.dev/pkg v0.0.0-20201204175509-c9bac6be76ca h1:A8Nly0CAT2J+oVs37pzRIqOiBqSGWPMGNXCNwGoUwkQ=
+knative.dev/pkg v0.0.0-20201204175509-c9bac6be76ca/go.mod h1:Jtbz2/1gB8EZgZA4VvabTxM+AcDt2WL2P0RaFnKcOX8=
 modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
 modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
 modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
diff --git a/pkg/activator/net/revision_backends.go b/pkg/activator/net/revision_backends.go
index 1dc4431a8..8e4e8001d 100644
--- a/pkg/activator/net/revision_backends.go
+++ b/pkg/activator/net/revision_backends.go
@@ -40,12 +40,12 @@ import (
 
 	network "knative.dev/networking/pkg"
 	pkgnet "knative.dev/networking/pkg/apis/networking"
+	"knative.dev/networking/pkg/prober"
 	endpointsinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/endpoints"
 	serviceinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/service"
 	"knative.dev/pkg/controller"
 	"knative.dev/pkg/logging"
 	"knative.dev/pkg/logging/logkey"
-	"knative.dev/pkg/network/prober"
 	"knative.dev/pkg/reconciler"
 	"knative.dev/serving/pkg/apis/serving"
 	revisioninformer "knative.dev/serving/pkg/client/injection/informers/serving/v1/revision"
diff --git a/pkg/apis/serving/v1alpha1/domainmapping_lifecycle.go b/pkg/apis/serving/v1alpha1/domainmapping_lifecycle.go
index 0f9f9e494..4ab88d439 100644
--- a/pkg/apis/serving/v1alpha1/domainmapping_lifecycle.go
+++ b/pkg/apis/serving/v1alpha1/domainmapping_lifecycle.go
@@ -27,6 +27,7 @@ var domainMappingCondSet = apis.NewLivingConditionSet(
 	DomainMappingConditionDomainClaimed,
 	DomainMappingConditionReferenceResolved,
 	DomainMappingConditionIngressReady,
+	DomainMappingConditionCertificateProvisioned,
 )
 
 // GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface.
@@ -57,6 +58,60 @@ func (dms *DomainMappingStatus) InitializeConditions() {
 	domainMappingCondSet.Manage(dms).InitializeConditions()
 }
 
+const (
+	// AutoTLSNotEnabledMessage is the message which is set on the
+	// DomainMappingConditionCertificateProvisioned condition when it is set to True
+	// because AutoTLS was not enabled.
+	AutoTLSNotEnabledMessage = "autoTLS is not enabled"
+)
+
+// MarkTLSNotEnabled sets DomainMappingConditionCertificateProvisioned to true when
+// certificate provisioning was skipped because TLS was not enabled.
+func (dms *DomainMappingStatus) MarkTLSNotEnabled(msg string) {
+	domainMappingCondSet.Manage(dms).MarkTrueWithReason(DomainMappingConditionCertificateProvisioned,
+		"TLSNotEnabled", msg)
+}
+
+// MarkCertificateReady marks the DomainMappingConditionCertificateProvisioned
+// condition to indicate that the Certificate is ready.
+func (dms *DomainMappingStatus) MarkCertificateReady(name string) {
+	domainMappingCondSet.Manage(dms).MarkTrue(DomainMappingConditionCertificateProvisioned)
+}
+
+// MarkCertificateNotReady marks the DomainMappingConditionCertificateProvisioned
+// condition to indicate that the Certificate is not ready.
+func (dms *DomainMappingStatus) MarkCertificateNotReady(name string) {
+	domainMappingCondSet.Manage(dms).MarkUnknown(DomainMappingConditionCertificateProvisioned,
+		"CertificateNotReady",
+		"Certificate %s is not ready.", name)
+}
+
+// MarkCertificateNotOwned changes the DomainMappingConditionCertificateProvisioned
+// status to be false with the reason being that there is an existing
+// certificate with the name we wanted to use.
+func (dms *DomainMappingStatus) MarkCertificateNotOwned(name string) {
+	domainMappingCondSet.Manage(dms).MarkFalse(DomainMappingConditionCertificateProvisioned,
+		"CertificateNotOwned",
+		"There is an existing certificate %s that we don't own.", name)
+}
+
+// MarkCertificateProvisionFailed marks the
+// DomainMappingConditionCertificateProvisioned condition to indicate that the
+// Certificate provisioning failed.
+func (dms *DomainMappingStatus) MarkCertificateProvisionFailed(name string) {
+	domainMappingCondSet.Manage(dms).MarkFalse(DomainMappingConditionCertificateProvisioned,
+		"CertificateProvisionFailed",
+		"Certificate %s failed to be provisioned.", name)
+}
+
+// MarkHTTPDowngrade sets DomainMappingConditionCertificateProvisioned to true when plain
+// HTTP is enabled even when Certificate is not ready.
+func (dms *DomainMappingStatus) MarkHTTPDowngrade(name string) {
+	domainMappingCondSet.Manage(dms).MarkTrueWithReason(DomainMappingConditionCertificateProvisioned,
+		"HTTPDowngrade",
+		"Certificate %s is not ready downgrade HTTP.", name)
+}
+
 // MarkIngressNotConfigured changes the IngressReady condition to be unknown to reflect
 // that the Ingress does not yet have a Status.
 func (dms *DomainMappingStatus) MarkIngressNotConfigured() {
diff --git a/pkg/apis/serving/v1alpha1/domainmapping_types.go b/pkg/apis/serving/v1alpha1/domainmapping_types.go
index 8421afdf0..0fa82ca95 100644
--- a/pkg/apis/serving/v1alpha1/domainmapping_types.go
+++ b/pkg/apis/serving/v1alpha1/domainmapping_types.go
@@ -106,6 +106,10 @@ const (
 	// DomainMappingConditionDomainClaimed reflects that the ClusterDomainClaim
 	// for this DomainMapping exists, and is owned by this DomainMapping.
 	DomainMappingConditionDomainClaimed apis.ConditionType = "DomainClaimed"
+
+	// DomainMappingConditionCertificateProvisioned is set to False when the
+	// Knative Certificates fail to be provisioned for the DomainMapping.
+	DomainMappingConditionCertificateProvisioned apis.ConditionType = "CertificateProvisioned"
 )
 
 // GetStatus retrieves the status of the DomainMapping. Implements the KRShaped interface.
diff --git a/pkg/reconciler/autoscaling/kpa/scaler.go b/pkg/reconciler/autoscaling/kpa/scaler.go
index 00954607e..104d1eae6 100644
--- a/pkg/reconciler/autoscaling/kpa/scaler.go
+++ b/pkg/reconciler/autoscaling/kpa/scaler.go
@@ -29,8 +29,8 @@ import (
 	network "knative.dev/networking/pkg"
 	"knative.dev/networking/pkg/apis/networking"
 	nv1a1 "knative.dev/networking/pkg/apis/networking/v1alpha1"
+	"knative.dev/networking/pkg/prober"
 	pkgnet "knative.dev/pkg/network"
-	"knative.dev/pkg/network/prober"
 	"knative.dev/serving/pkg/activator"
 	pav1alpha1 "knative.dev/serving/pkg/apis/autoscaling/v1alpha1"
 	"knative.dev/serving/pkg/autoscaler/config/autoscalerconfig"
diff --git a/pkg/reconciler/domainmapping/reconciler.go b/pkg/reconciler/domainmapping/reconciler.go
index 17ec099b6..f0da3bdfa 100644
--- a/pkg/reconciler/domainmapping/reconciler.go
+++ b/pkg/reconciler/domainmapping/reconciler.go
@@ -58,6 +58,9 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, dm *v1alpha1.DomainMappi
 	logger := logging.FromContext(ctx)
 	logger.Debugf("Reconciling DomainMapping %s/%s", dm.Namespace, dm.Name)
 
+	// TODO(https://github.com/knative/serving/issues/10247)
+	dm.Status.MarkTLSNotEnabled("AutoTLS for DomainMapping is not implemented")
+
 	// Defensively assume the ingress is not configured until we manage to
 	// successfully reconcile it below. This avoids error cases where we fail
 	// before we've reconciled the ingress and get a new ObservedGeneration but
diff --git a/pkg/reconciler/route/reconcile_resources.go b/pkg/reconciler/route/reconcile_resources.go
index 14a91c791..e84c373b5 100644
--- a/pkg/reconciler/route/reconcile_resources.go
+++ b/pkg/reconciler/route/reconcile_resources.go
@@ -21,7 +21,9 @@ import (
 	"encoding/json"
 	"fmt"
 
+	"github.com/google/go-cmp/cmp"
 	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
 	"golang.org/x/sync/errgroup"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/equality"
@@ -77,9 +79,19 @@ func (c *Reconciler) reconcileIngress(
 		// And recompute the rollout state.
 		effectiveRO := curRO.Step(prevRO, int(c.clock.Now().UnixNano()))
 
+		// Comparing and diffing isn't cheap so do it only if we're going
+		// to actually log the message.
+		// Those are well known types, cmp won't panic.
+		logger := logging.FromContext(ctx).Desugar()
+		if logger.Core().Enabled(zapcore.DebugLevel) && !cmp.Equal(prevRO, effectiveRO) {
+			logger.Debug("Rollout diff:(-was,+now)",
+				zap.String("diff", cmp.Diff(prevRO, effectiveRO)))
+		}
+
 		// Now check if the ingress status changed from not ready to ready.
 		rtView := r.Status.GetCondition(v1.RouteConditionIngressReady)
 		if ingress.IsReady() && !rtView.IsTrue() {
+			logger.Debug("Observing Ingress not-ready to ready switch condition for rollout")
 			effectiveRO.ObserveReady(int(c.clock.Now().UnixNano()))
 		}
 
@@ -92,13 +104,14 @@ func (c *Reconciler) reconcileIngress(
 		if !equality.Semantic.DeepEqual(ingress.Spec, desired.Spec) ||
 			!equality.Semantic.DeepEqual(ingress.Annotations, desired.Annotations) ||
 			!equality.Semantic.DeepEqual(ingress.Labels, desired.Labels) {
+
 			// It is notable that one reason for differences here may be defaulting.
 			// When that is the case, the Update will end up being a nop because the
 			// webhook will bring them into alignment and no new reconciliation will occur.
 			// Also, compare annotation and label in case ingress.Class or parent route's labels
 			// is updated.
 
-			// Don't modify the informers copy
+			// Don't modify the informers copy.
 			origin := ingress.DeepCopy()
 			origin.Spec = desired.Spec
 			origin.Annotations = desired.Annotations
diff --git a/pkg/reconciler/route/traffic/rollout.go b/pkg/reconciler/route/traffic/rollout.go
index 3616159af..c9ac44c38 100644
--- a/pkg/reconciler/route/traffic/rollout.go
+++ b/pkg/reconciler/route/traffic/rollout.go
@@ -67,14 +67,17 @@ type ConfigurationRollout struct {
 	// This is required to compute step time and deadline.
 	StartTime int `json:"starttime,omitempty"`
 
-	// LastStepTimeStamp is the Unix timestamp when the last
-	// rollout step was performed.
-	LastStepTime int `json:"lastStep,omitempty"`
+	// NextStepTime is the Unix timestamp when the next
+	// rollout step should performed.
+	NextStepTime int `json:"nextStepTime,omitempty"`
 
 	// StepDuration is a rounded up number of seconds how long it took
 	// for ingress to successfully move first 1% of traffic to the new revision.
 	// Note, that his number does not include any coldstart, etc timing.
 	StepDuration int `json:"stepDuration,omitempty"`
+
+	// How much traffic to move in a single step.
+	StepSize int `json:"stepSize,omitempty"`
 }
 
 // RevisionRollout describes the revision in the config rollout.
@@ -89,9 +92,9 @@ type RevisionRollout struct {
 
 // Done returns true if there is no active rollout going on
 // for the configuration.
-func (cr *ConfigurationRollout) Done() bool {
+func (cur *ConfigurationRollout) Done() bool {
 	// Zero or just one revision.
-	return len(cr.Revisions) < 2
+	return len(cur.Revisions) < 2
 }
 
 // Validate validates current rollout for inconsistencies.
@@ -115,15 +118,21 @@ func (cur *Rollout) Validate() bool {
 	return true
 }
 
+// TODO(vagababov): default fake rollout duration in use, while we
+// only modify the annotation and do not actually modify the traffic.
+const durationSecs = 120.0
+
 // ObserveReady traverses the configs and the ones that are in rollout
 // but have not observed step time yet, will have it set, to
-// max(1, nowTS-cfg.StartTime). nowTS is unix timestamp in ns.
+// max(1, nowTS-cfg.StartTime).
 func (cur *Rollout) ObserveReady(nowTS int) {
 	for i := range cur.Configurations {
 		c := &cur.Configurations[i]
 		if c.StepDuration == 0 && c.StartTime > 0 {
-			c.StepDuration = int(math.Max(1,
-				math.Ceil(time.Duration(nowTS-c.StartTime).Seconds())))
+			// In really ceil(nowTS-c.StartTime) should always give 1s, but
+			// given possible time drift, we'll ensure that at least 1s is returned.
+			minStepSec := math.Max(1, math.Ceil(time.Duration(nowTS-c.StartTime).Seconds()))
+			c.computeProperties(float64(nowTS), minStepSec, durationSecs)
 		}
 	}
 }
@@ -133,7 +142,6 @@ func (cur *Rollout) ObserveReady(nowTS int) {
 // At the end of the call the returned object will contain the
 // desired traffic shape.
 // Step will return cur if no previous state was available.
-// nowTS is unix timestamp in ns.
 func (cur *Rollout) Step(prev *Rollout, nowTS int) *Rollout {
 	if prev == nil || len(prev.Configurations) == 0 {
 		return cur
@@ -188,7 +196,7 @@ func (cur *Rollout) Step(prev *Rollout, nowTS int) *Rollout {
 				j++
 			case ccfgs[i].ConfigurationName < pcfgs[j].ConfigurationName:
 				// A new config, has been added. No action for rollout though.
-				// Keep it if it will receive traffic.
+				// Keep it for future rollout actions.
 				if ccfgs[i].Percent != 0 {
 					ret = append(ret, *ccfgs[i])
 				}
@@ -214,6 +222,8 @@ func (cur *Rollout) Step(prev *Rollout, nowTS int) *Rollout {
 // the older revisions.
 func adjustPercentage(goal int, cr *ConfigurationRollout) {
 	switch diff := goal - cr.Percent; {
+	case goal == 0:
+		cr.Revisions = nil // No traffic, no rollout.
 	case diff > 0:
 		cr.Revisions[len(cr.Revisions)-1].Percent += diff
 	case diff < 0:
@@ -233,6 +243,65 @@ func adjustPercentage(goal int, cr *ConfigurationRollout) {
 	}
 }
 
+// stepRevisions performs re-adjustment of percentages on the revisions
+// to rollout more traffic to the last one.
+func stepRevisions(goal *ConfigurationRollout, nowTS int) {
+	// Not yet ready to adjust the steps or we're done
+	// (shouldn't really be here, but better be defensive).
+	if nowTS < goal.NextStepTime || len(goal.Revisions) < 2 {
+		return
+	}
+
+	revLen := len(goal.Revisions)
+	remaining := goal.StepSize
+	writePos := revLen - 1
+	// readPos is guaranteed to be >= 0, due to the check above.
+	readPos := revLen - 2
+
+	// If step > totalPercent then remaining will always be > 0
+	// even after readPos == -1.
+	// This is the case when config's target is reduced below step size.
+	// E.g. was: R1 = 40 R2 = 10 Step = 10 Total=60
+	// Now = Total = 15;
+	// After adjust percentage: R1 = 5 R2 = 10
+	// Then after first iteration R1 = 0, remaining = 5.
+	// We'll handle this situation below.
+	for remaining > 0 && readPos >= 0 {
+		// If this revision's allocation is strictly larger than the goal,
+		// just subtract the different and we're done.
+		if goal.Revisions[readPos].Percent > remaining {
+			goal.Revisions[readPos].Percent -= remaining
+			break
+		}
+		// Otherwise subtract what is possible and update
+		// write position since this revision will no longer
+		// receive traffic.
+		remaining -= goal.Revisions[readPos].Percent
+		writePos--
+		readPos--
+	}
+	// Copy the last one to the write pos
+	goal.Revisions[writePos] = goal.Revisions[revLen-1]
+
+	goal.Revisions[writePos].Percent += goal.StepSize
+	// This can happen if step is now larger than total allocation, see the
+	// note above.
+	// E.g. with example above R2 = 20, and ro we have to cap it at 15.
+	if goal.Revisions[writePos].Percent > goal.Percent {
+		goal.Revisions[writePos].Percent = goal.Percent
+	}
+	// And cull the tail portion of it.
+	goal.Revisions = goal.Revisions[:writePos+1]
+	// Also set the next time.
+	if len(goal.Revisions) > 1 {
+		goal.NextStepTime = nowTS + goal.StepDuration
+	} else {
+		// This is the last step, we're done!
+		goal.NextStepTime = 0
+		goal.StartTime = 0
+	}
+}
+
 // stepConfig takes previous and goal configuration shapes and returns a new
 // config rollout, after computing the percetage allocations.
 func stepConfig(goal, prev *ConfigurationRollout, nowTS int) *ConfigurationRollout {
@@ -254,22 +323,37 @@ func stepConfig(goal, prev *ConfigurationRollout, nowTS int) *ConfigurationRollo
 	// If it matches the last revision of the previous rollout state (or there were no revisions)
 	// then no new rollout has begun for this configuration.
 	if len(prev.Revisions) == 0 || goal.Revisions[0].RevisionName == prev.Revisions[pc-1].RevisionName {
-		if len(prev.Revisions) > 0 {
+		// So if |prev.revisions| == 0 => then there was no rollout —
+		// nothing is required to step.
+		// If |prev.revisions| == 1 and it matches current revision then
+		// we're done.
+		// Thus we need to perform work only if there is more than one
+		// revision in the previous state.
+		if len(prev.Revisions) > 1 {
 			ret.Revisions = prev.Revisions
 
-			// TODO(vagababov): here would go the logic to compute new percentages for the rollout,
-			// i.e step function, so return value will change, depending on that.
-			// Copy the duration info from the previous when no new revision
+			// Copy various rollout stats from the previous when no new revision
 			// has been created.
+			ret.StartTime = prev.StartTime
 			ret.Deadline = prev.Deadline
-			ret.LastStepTime = prev.LastStepTime
+			ret.NextStepTime = prev.NextStepTime
 			ret.StepDuration = prev.StepDuration
-			ret.StartTime = prev.StartTime
+			ret.StepSize = prev.StepSize
+			// We might end up here before `ObserveReady` is called.
+			// In that case don't step individual revisions just yet.
+			if ret.StepSize > 0 {
+				// adjustPercentage above would've already accounted if target for the
+				// whole Configuration changed up or down. So here we should just redistribute
+				// the existing values.
+				stepRevisions(ret, nowTS)
+			}
 		}
 		return ret
 	}
 
-	// Otherwise we start a rollout, which means we need to stamp the starttime.
+	// Otherwise we start a rollout, which means we need to stamp the starttime,
+	// the rest of the fields will remain unset and `ObserveReady` will
+	// compute them when the ingress becomes ready.
 	ret.StartTime = nowTS
 
 	// Go backwards and find first revision with traffic assignment > 0.
@@ -304,6 +388,40 @@ func stepConfig(goal, prev *ConfigurationRollout, nowTS int) *ConfigurationRollo
 	return ret
 }
 
+// computeProperties computes the time between steps, each step size
+// and next reconcile time. This is invoked when the rollout just starts.
+// nowTS current unix timestamp in ns.
+// Pre: minStepSec >= 1, in seconds.
+// Pre: durationSecs > 1, in seconds.
+func (cur *ConfigurationRollout) computeProperties(nowTS, minStepSec, durationSecs float64) {
+	// First compute number of steps.
+	numSteps := durationSecs / minStepSec
+	pf := float64(cur.Percent)
+
+	// The smallest step is 1%, so if we can fit more steps
+	// than we have percents, we'll make c.Percent-1 steps
+	// each equal to 1%. -1, since we already moved 1% of the traffic.
+	if pf < numSteps {
+		numSteps = pf - 1
+	}
+
+	// We're moving traffic in equal steps.
+	// The last step can be larger, since it's more likely to
+	// easily accommodate the traffic jump, due to built in
+	// spare capacity.
+	// E.g. 100% in 4 steps. 1% -> 25% -> 49% -> 74% -> 100%, last jump being 26%.
+	stepSize := math.Floor((pf - 1) / numSteps)
+
+	// The time we sleep between the steps.
+	// We round up here since it's better to roll slightly longer,
+	// than slightly shorter.
+	stepDuration := math.Ceil(durationSecs / numSteps)
+
+	cur.StepDuration = int(stepDuration)
+	cur.StepSize = int(stepSize)
+	cur.NextStepTime = int(nowTS + stepDuration*float64(time.Second))
+}
+
 // sortRollout sorts the rollout based on tag so it's consistent
 // from run to run, since input to the process is map iterator.
 func sortRollout(r *Rollout) {
diff --git a/third_party/VENDOR-LICENSE/github.com/blendle/zapdriver/LICENSE b/third_party/VENDOR-LICENSE/github.com/blendle/zapdriver/LICENSE
new file mode 100644
index 000000000..7db456775
--- /dev/null
+++ b/third_party/VENDOR-LICENSE/github.com/blendle/zapdriver/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) Blendle
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/blendle/zapdriver/.gitignore b/vendor/github.com/blendle/zapdriver/.gitignore
new file mode 100644
index 000000000..48b8bf907
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/.gitignore
@@ -0,0 +1,1 @@
+vendor/
diff --git a/vendor/github.com/blendle/zapdriver/LICENSE b/vendor/github.com/blendle/zapdriver/LICENSE
new file mode 100644
index 000000000..7db456775
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) Blendle
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/blendle/zapdriver/README.md b/vendor/github.com/blendle/zapdriver/README.md
new file mode 100644
index 000000000..8044c5523
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/README.md
@@ -0,0 +1,347 @@
+# :zap: Zapdriver
+
+Blazing fast, [Zap][zap]-based [Stackdriver][stackdriver] logging.
+
+[zap]: https://github.com/uber-go/zap
+[stackdriver]: https://cloud.google.com/stackdriver/
+
+## Usage
+
+This package provides three building blocks to support the full array of
+structured logging capabilities of Stackdriver:
+
+* [Special purpose logging fields](#special-purpose-logging-fields)
+* [Pre-configured Stackdriver-optimized encoder](#pre-configured-stackdriver-optimized-encoder)
+* [Custom Stackdriver Zap core](#custom-stackdriver-zap-core)
+* [Using Error Reporting](#using-error-reporting)
+
+The above components can be used separately, but to start, you can create a new
+Zap logger with all of the above included:
+
+```golang
+logger, err := zapdriver.NewProduction() // with sampling
+logger, err := zapdriver.NewDevelopment() // with `development` set to `true`
+```
+
+The above functions give back a pointer to a `zap.Logger` object, so you can use
+[Zap][zap] like you've always done, except that it now logs in the proper
+[Stackdriver][stackdriver] format.
+
+You can also create a configuration struct, and build your logger from there:
+
+```golang
+config := zapdriver.NewProductionConfig()
+config := zapdriver.NewDevelopmentConfig()
+```
+
+Or, get the Zapdriver encoder, and build your own configuration struct from
+that:
+
+```golang
+encoder := zapdriver.NewProductionEncoderConfig()
+encoder := zapdriver.NewDevelopmentEncoderConfig()
+```
+
+Read on to learn more about the available Stackdriver-specific log fields, and
+how to use the above-mentioned components.
+
+### Special purpose logging fields
+
+You can use the following fields to add extra information to your log entries.
+These fields are parsed by Stackdriver to make it easier to query your logs or
+to use the log details in the Stackdriver monitoring interface.
+
+* [`HTTP`](#http)
+* [`Label`](#label)
+* [`SourceLocation`](#sourcelocation)
+* [`Operation`](#operation)
+* [`TraceContext`](#tracecontext)
+
+#### HTTP
+
+You can log HTTP request/response cycles using the following field:
+
+```golang
+HTTP(req *HTTPPayload) zap.Field
+```
+
+You can either manually build the request payload:
+
+```golang
+req := &HTTPPayload{
+  RequestMethod: "GET",
+  RequestURL: "/",
+  Status: 200,
+}
+```
+
+Or, you can auto generate the struct, based on the available request and
+response objects:
+
+```golang
+NewHTTP(req *http.Request, res *http.Response) *HTTPPayload
+```
+
+You are free to pass in `nil` for either the request or response object, if one
+of them is unavailable to you at the point of logging. Any field depending on
+one or the other will be omitted if `nil` is passed in.
+
+Note that there are some fields that are not populated by either the request or
+response object, and need to be set manually:
+
+* `ServerIP string`
+* `Latency string`
+* `CacheLookup bool`
+* `CacheHit bool`
+* `CacheValidatedWithOriginServer bool`
+* `CacheFillBytes string`
+
+If you have no need for those fields, the quickest way to get started is like
+so:
+
+```golang
+logger.Info("Request Received.", zapdriver.HTTP(zapdriver.NewHTTP(req, res)))
+```
+
+#### Label
+
+You can add a "label" to your payload as follows:
+
+```golang
+Label(key, value string) zap.Field
+```
+
+Note that underwater, this sets the key to `labels.<key>`. You need to be using
+the `zapdriver.Core` core for this to be converted to the proper format for
+Stackdriver to recognize the labels.
+
+See "Custom Stackdriver Zap core" for more details.
+
+If you have a reason not to use the provided Core, you can still wrap labels in
+the right `labels` namespace by using the available function:
+
+```golang
+Labels(fields ...zap.Field) zap.Field
+```
+
+Like so:
+
+```golang
+logger.Info(
+  "Did something.",
+  zapdriver.Labels(
+    zapdriver.Label("hello", "world"),
+    zapdriver.Label("hi", "universe"),
+  ),
+)
+```
+
+Again, wrapping the `Label` calls in `Labels` is not required if you use the
+supplied Zap Core.
+
+#### SourceLocation
+
+You can add a source code location to your log lines to be picked up by
+Stackdriver.
+
+Note that you can set this manually, or use `zapdriver.Core` to automatically
+add this. If you set it manually, _and_ use `zapdriver.Core`, the manual call
+stack will be preserved over the automated one.
+
+```golang
+SourceLocation(pc uintptr, file string, line int, ok bool) zap.Field
+```
+
+Note that the function signature equals that of the return values of
+`runtime.Caller()`. This allows you to catch the stack frame at one location,
+while logging it at a different location, like so:
+
+```golang
+pc, file, line, ok := runtime.Caller(0)
+
+// do other stuff...
+
+logger.Error("Something happened!", zapdriver.SourceLocation(pc, file, line, ok))
+```
+
+If you use `zapdriver.Core`, the above use-case is the only use-case where you
+would want to manually set the source location. In all other situations, you can
+simply omit this field, and it will be added automatically, using the stack
+frame at the location where the log line is triggered.
+
+If you don't use `zapdriver.Core`, and still want to add the source location at
+the frame of the triggered log line, you'd do it like this:
+
+```golang
+logger.Error("Something happened!", zapdriver.SourceLocation(runtime.Caller(0)))
+```
+
+#### Operation
+
+The `Operation` log field allows you to group log lines into a single
+"operation" performed by the application:
+
+```golang
+Operation(id, producer string, first, last bool) zap.Field
+```
+
+For a pair of logs that belong to the same operation, you should use the same
+`id` between them. The `producer` is an arbitrary identifier that should be
+globally unique amongst all the logs of all your applications (meaning it should
+probably be the unique name of the current application). You should set `first`
+to true for the first log in the operation, and `last` to true for the final log
+of the operation.
+
+```golang
+logger.Info("Started.", zapdriver.Operation("3g4d3g", "my-app", true, false))
+logger.Debug("Progressing.", zapdriver.Operation("3g4d3g", "my-app", false, false))
+logger.Info("Done.", zapdriver.Operation("3g4d3g", "my-app", false, true))
+```
+
+Instead of defining the "start" and "end" booleans, you can also use these three
+convenience functions:
+
+```golang
+OperationStart(id, producer string) zap.Field
+OperationCont(id, producer string) zap.Field
+OperationEnd(id, producer string) zap.Field
+```
+
+#### TraceContext
+
+You can add trace context information to your log lines to be picked up by
+Stackdriver.
+
+```golang
+TraceContext(trace string, spanId string, sampled bool, projectName string) []zap.Field
+```
+
+Like so:
+
+```golang
+logger.Error("Something happened!", zapdriver.TraceContext("105445aa7843bc8bf206b120001000", "0", true, "my-project-name")...)
+```
+
+### Pre-configured Stackdriver-optimized encoder
+
+The Stackdriver encoder maps all Zap log levels to the appropriate
+[Stackdriver-supported levels][levels]:
+
+> DEBUG     (100) Debug or trace information.
+>
+> INFO      (200) Routine information, such as ongoing status or performance.
+>
+> WARNING   (400) Warning events might cause problems.
+>
+> ERROR     (500) Error events are likely to cause problems.
+>
+> CRITICAL  (600) Critical events cause more severe problems or outages.
+>
+> ALERT     (700) A person must take an action immediately.
+>
+> EMERGENCY (800) One or more systems are unusable.
+
+[levels]: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity
+
+It also sets some of the default keys to use [the right names][names], such as
+`timestamp`, `severity`, and `message`.
+
+[names]: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
+
+You can use this encoder if you want to build your Zap logger configuration
+manually:
+
+```golang
+zapdriver.NewProductionEncoderConfig()
+```
+
+For parity-sake, there's also `zapdriver.NewDevelopmentEncoderConfig()`, but it
+returns the exact same encoder right now.
+
+### Custom Stackdriver Zap core
+
+A custom Zap core is included in this package to support some special use-cases.
+
+First of all, if you use `zapdriver.NewProduction()` (or `NewDevelopment`) , you
+already have this core enabled, so everything _just works_ ™.
+
+There are two use-cases which require this core:
+
+1. If you use `zapdriver.Label("hello", "world")`, it will initially end up in
+   your log with the key `labels.hello` and value `world`. Now if you have two
+   labels, you could also have `labels.hi` with value `universe`. This works as-
+   is, but for this to be correctly parsed by Stackdriver as true "labels", you
+   need to use the Zapdriver core, so that both of these fields get rewritten,
+   to use the namespace `labels`, and use the keys `hello` and `hi` within that
+   namespace. This is done automatically.
+
+2. If you don't want to use `zapdriver.SourceLocation()` on every log call, you
+   can use this core for the source location to be automatically added to
+   each log entry.
+
+When building a logger, you can inject the Zapdriver core as follows:
+
+```golang
+config := &zap.Config{}
+logger, err := config.Build(zapdriver.WrapCore())
+```
+
+### Using Error Reporting
+
+To report errors using StackDriver's Error Reporting tool, a log line needs to follow a separate log format described in the [Error Reporting][errorreporting] documentation.
+
+[errorreporting]: https://cloud.google.com/error-reporting/docs/formatting-error-messages
+
+The simplest way to do this is by using `NewProductionWithCore`:
+
+```golang
+logger, err := zapdriver.NewProductionWithCore(zapdriver.WrapCore(
+  zapdriver.ReportAllErrors(true),
+  zapdriver.ServiceName("my service"),
+))
+```
+
+For parity-sake, there's also `zapdriver.NewDevelopmentWithCore()`
+
+If you are building a custom logger, you can use `WrapCore()` to configure the driver core:
+
+```golang
+config := &zap.Config{}
+logger, err := config.Build(zapdriver.WrapCore(
+  zapdriver.ReportAllErrors(true),
+  zapdriver.ServiceName("my service"),
+))
+```
+
+Configuring this way, every error log entry will be reported to Stackdriver's Error Reporting tool.
+
+#### Reporting errors manually
+
+If you do not want every error to be reported, you can attach `ErrorReport()` to log call manually:
+
+```golang
+logger.Error("An error to be reported!", zapdriver.ErrorReport(runtime.Caller(0)))
+// Or get Caller details
+pc, file, line, ok := runtime.Caller(0)
+// do other stuff... and log elsewhere
+logger.Error("Another error to be reported!", zapdriver.ErrorReport(pc, file, line, ok))
+```
+
+Please keep in mind that ErrorReport needs a ServiceContext attached to the log
+entry. If you did not configure this using `WrapCore`, error reports will
+get attached using service name as `unknown`. To prevent this from happeneing,
+either configure your core or attach service context before (or when) using
+the logger:
+
+```golang
+logger.Error(
+  "An error to be reported!",
+  zapdriver.ErrorReport(runtime.Caller(0)),
+  zapdriver.ServiceContext("my service"),
+)
+
+// Or permanently attach it to your logger
+logger = logger.With(zapdriver.ServiceContext("my service"))
+// and then use it
+logger.Error("An error to be reported!", zapdriver.ErrorReport(runtime.Caller(0)))
+```
diff --git a/vendor/github.com/blendle/zapdriver/config.go b/vendor/github.com/blendle/zapdriver/config.go
new file mode 100644
index 000000000..fe901ce3b
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/config.go
@@ -0,0 +1,55 @@
+package zapdriver
+
+import (
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+// NewProductionEncoderConfig returns an opinionated EncoderConfig for
+// production environments.
+func NewProductionEncoderConfig() zapcore.EncoderConfig {
+	return encoderConfig
+}
+
+// NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for
+// development environments.
+func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
+	return encoderConfig
+}
+
+// NewProductionConfig is a reasonable production logging configuration.
+// Logging is enabled at InfoLevel and above.
+//
+// It uses a JSON encoder, writes to standard error, and enables sampling.
+// Stacktraces are automatically included on logs of ErrorLevel and above.
+func NewProductionConfig() zap.Config {
+	return zap.Config{
+		Level:       zap.NewAtomicLevelAt(zap.InfoLevel),
+		Development: false,
+		Sampling: &zap.SamplingConfig{
+			Initial:    100,
+			Thereafter: 100,
+		},
+		Encoding:         "json",
+		EncoderConfig:    NewProductionEncoderConfig(),
+		OutputPaths:      []string{"stderr"},
+		ErrorOutputPaths: []string{"stderr"},
+	}
+}
+
+// NewDevelopmentConfig is a reasonable development logging configuration.
+// Logging is enabled at DebugLevel and above.
+//
+// It enables development mode (which makes DPanicLevel logs panic), uses a
+// console encoder, writes to standard error, and disables sampling.
+// Stacktraces are automatically included on logs of WarnLevel and above.
+func NewDevelopmentConfig() zap.Config {
+	return zap.Config{
+		Level:            zap.NewAtomicLevelAt(zap.DebugLevel),
+		Development:      true,
+		Encoding:         "json",
+		EncoderConfig:    NewDevelopmentEncoderConfig(),
+		OutputPaths:      []string{"stderr"},
+		ErrorOutputPaths: []string{"stderr"},
+	}
+}
diff --git a/vendor/github.com/blendle/zapdriver/core.go b/vendor/github.com/blendle/zapdriver/core.go
new file mode 100644
index 000000000..bcb7660f7
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/core.go
@@ -0,0 +1,243 @@
+package zapdriver
+
+import (
+	"strings"
+
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+// driverConfig is used to configure core.
+type driverConfig struct {
+	// Report all logs with level error or above to stackdriver using
+	// `ErrorReport()` when set to true
+	ReportAllErrors bool
+
+	// ServiceName is added as `ServiceContext()` to all logs when set
+	ServiceName string
+}
+
+// Core is a zapdriver specific core wrapped around the default zap core. It
+// allows to merge all defined labels
+type core struct {
+	zapcore.Core
+
+	// permLabels is a collection of labels that have been added to the logger
+	// through the use of `With()`. These labels should never be cleared after
+	// logging a single entry, unlike `tempLabel`.
+	permLabels *labels
+
+	// tempLabels keeps a record of all the labels that need to be applied to the
+	// current log entry. Zap serializes log fields at different parts of the
+	// stack, one such location is when calling `core.With` and the other one is
+	// when calling `core.Write`. This makes it impossible to (for example) take
+	// all `labels.xxx` fields, and wrap them in the `labels` namespace in one go.
+	//
+	// Instead, we have to filter out these labels at both locations, and then add
+	// them back in the proper format right before we call `Write` on the original
+	// Zap core.
+	tempLabels *labels
+
+	// Configuration for the zapdriver core
+	config driverConfig
+}
+
+// zapdriver core option to report all logs with level error or above to stackdriver
+// using `ErrorReport()` when set to true
+func ReportAllErrors(report bool) func(*core) {
+	return func(c *core) {
+		c.config.ReportAllErrors = report
+	}
+}
+
+// zapdriver core option to add `ServiceContext()` to all logs with `name` as
+// service name
+func ServiceName(name string) func(*core) {
+	return func(c *core) {
+		c.config.ServiceName = name
+	}
+}
+
+// WrapCore returns a `zap.Option` that wraps the default core with the
+// zapdriver one.
+func WrapCore(options ...func(*core)) zap.Option {
+	return zap.WrapCore(func(c zapcore.Core) zapcore.Core {
+		newcore := &core{
+			Core:       c,
+			permLabels: newLabels(),
+			tempLabels: newLabels(),
+		}
+		for _, option := range options {
+			option(newcore)
+		}
+		return newcore
+	})
+}
+
+// With adds structured context to the Core.
+func (c *core) With(fields []zap.Field) zapcore.Core {
+	var lbls *labels
+	lbls, fields = c.extractLabels(fields)
+
+	lbls.mutex.RLock()
+	c.permLabels.mutex.Lock()
+	for k, v := range lbls.store {
+		c.permLabels.store[k] = v
+	}
+	c.permLabels.mutex.Unlock()
+	lbls.mutex.RUnlock()
+
+	return &core{
+		Core:       c.Core.With(fields),
+		permLabels: c.permLabels,
+		tempLabels: newLabels(),
+		config:     c.config,
+	}
+}
+
+// Check determines whether the supplied Entry should be logged (using the
+// embedded LevelEnabler and possibly some extra logic). If the entry
+// should be logged, the Core adds itself to the CheckedEntry and returns
+// the result.
+//
+// Callers must use Check before calling Write.
+func (c *core) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
+	if c.Enabled(ent.Level) {
+		return ce.AddCore(ent, c)
+	}
+
+	return ce
+}
+
+func (c *core) Write(ent zapcore.Entry, fields []zapcore.Field) error {
+	var lbls *labels
+	lbls, fields = c.extractLabels(fields)
+
+	lbls.mutex.RLock()
+	c.tempLabels.mutex.Lock()
+	for k, v := range lbls.store {
+		c.tempLabels.store[k] = v
+	}
+	c.tempLabels.mutex.Unlock()
+	lbls.mutex.RUnlock()
+
+	fields = append(fields, labelsField(c.allLabels()))
+	fields = c.withSourceLocation(ent, fields)
+	if c.config.ServiceName != "" {
+		fields = c.withServiceContext(c.config.ServiceName, fields)
+	}
+	if c.config.ReportAllErrors && zapcore.ErrorLevel.Enabled(ent.Level) {
+		fields = c.withErrorReport(ent, fields)
+		if c.config.ServiceName == "" {
+			// A service name was not set but error report needs it
+			// So attempt to add a generic service name
+			fields = c.withServiceContext("unknown", fields)
+		}
+	}
+
+	c.tempLabels.reset()
+
+	return c.Core.Write(ent, fields)
+}
+
+// Sync flushes buffered logs (if any).
+func (c *core) Sync() error {
+	return c.Core.Sync()
+}
+
+func (c *core) allLabels() *labels {
+	lbls := newLabels()
+
+	lbls.mutex.Lock()
+	c.permLabels.mutex.RLock()
+	for k, v := range c.permLabels.store {
+		lbls.store[k] = v
+	}
+	c.permLabels.mutex.RUnlock()
+
+	c.tempLabels.mutex.RLock()
+	for k, v := range c.tempLabels.store {
+		lbls.store[k] = v
+	}
+	c.tempLabels.mutex.RUnlock()
+	lbls.mutex.Unlock()
+
+	return lbls
+}
+
+func (c *core) extractLabels(fields []zapcore.Field) (*labels, []zapcore.Field) {
+	lbls := newLabels()
+	out := []zapcore.Field{}
+
+	lbls.mutex.Lock()
+	for i := range fields {
+		if !isLabelField(fields[i]) {
+			out = append(out, fields[i])
+			continue
+		}
+
+		lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String
+	}
+	lbls.mutex.Unlock()
+
+	return lbls, out
+}
+
+func (c *core) withLabels(fields []zapcore.Field) []zapcore.Field {
+	lbls := newLabels()
+	out := []zapcore.Field{}
+
+	lbls.mutex.Lock()
+	for i := range fields {
+		if isLabelField(fields[i]) {
+			lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String
+			continue
+		}
+
+		out = append(out, fields[i])
+	}
+	lbls.mutex.Unlock()
+
+	return append(out, labelsField(lbls))
+}
+
+func (c *core) withSourceLocation(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field {
+	// If the source location was manually set, don't overwrite it
+	for i := range fields {
+		if fields[i].Key == sourceKey {
+			return fields
+		}
+	}
+
+	if !ent.Caller.Defined {
+		return fields
+	}
+
+	return append(fields, SourceLocation(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true))
+}
+
+func (c *core) withServiceContext(name string, fields []zapcore.Field) []zapcore.Field {
+	// If the service context was manually set, don't overwrite it
+	for i := range fields {
+		if fields[i].Key == serviceContextKey {
+			return fields
+		}
+	}
+
+	return append(fields, ServiceContext(name))
+}
+
+func (c *core) withErrorReport(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field {
+	// If the error report was manually set, don't overwrite it
+	for i := range fields {
+		if fields[i].Key == contextKey {
+			return fields
+		}
+	}
+
+	if !ent.Caller.Defined {
+		return fields
+	}
+
+	return append(fields, ErrorReport(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true))
+}
diff --git a/vendor/github.com/blendle/zapdriver/encoder.go b/vendor/github.com/blendle/zapdriver/encoder.go
new file mode 100644
index 000000000..eec571fb8
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/encoder.go
@@ -0,0 +1,59 @@
+package zapdriver
+
+import (
+	"time"
+
+	"go.uber.org/zap/zapcore"
+)
+
+// logLevelSeverity maps the Zap log levels to the correct level names as
+// defined by Stackdriver.
+//
+// DEFAULT     (0) The log entry has no assigned severity level.
+// DEBUG     (100) Debug or trace information.
+// INFO      (200) Routine information, such as ongoing status or performance.
+// NOTICE    (300) Normal but significant events, such as start up, shut down, or a configuration change.
+// WARNING   (400) Warning events might cause problems.
+// ERROR     (500) Error events are likely to cause problems.
+// CRITICAL  (600) Critical events cause more severe problems or outages.
+// ALERT     (700) A person must take an action immediately.
+// EMERGENCY (800) One or more systems are unusable.
+//
+// See: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity
+var logLevelSeverity = map[zapcore.Level]string{
+	zapcore.DebugLevel:  "DEBUG",
+	zapcore.InfoLevel:   "INFO",
+	zapcore.WarnLevel:   "WARNING",
+	zapcore.ErrorLevel:  "ERROR",
+	zapcore.DPanicLevel: "CRITICAL",
+	zapcore.PanicLevel:  "ALERT",
+	zapcore.FatalLevel:  "EMERGENCY",
+}
+
+// encoderConfig is the default encoder configuration, slightly tweaked to use
+// the correct fields for Stackdriver to parse them.
+var encoderConfig = zapcore.EncoderConfig{
+	TimeKey:        "timestamp",
+	LevelKey:       "severity",
+	NameKey:        "logger",
+	CallerKey:      "caller",
+	MessageKey:     "message",
+	StacktraceKey:  "stacktrace",
+	LineEnding:     zapcore.DefaultLineEnding,
+	EncodeLevel:    EncodeLevel,
+	EncodeTime:     RFC3339NanoTimeEncoder,
+	EncodeDuration: zapcore.SecondsDurationEncoder,
+	EncodeCaller:   zapcore.ShortCallerEncoder,
+}
+
+// EncodeLevel maps the internal Zap log level to the appropriate Stackdriver
+// level.
+func EncodeLevel(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
+	enc.AppendString(logLevelSeverity[l])
+}
+
+// RFC3339NanoTimeEncoder serializes a time.Time to an RFC3339Nano-formatted
+// string with nanoseconds precision.
+func RFC3339NanoTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
+	enc.AppendString(t.Format(time.RFC3339Nano))
+}
diff --git a/vendor/github.com/blendle/zapdriver/go.mod b/vendor/github.com/blendle/zapdriver/go.mod
new file mode 100644
index 000000000..aecbd4f12
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/go.mod
@@ -0,0 +1,12 @@
+module github.com/blendle/zapdriver
+
+go 1.12
+
+require (
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/pkg/errors v0.8.1 // indirect
+	github.com/stretchr/testify v1.3.0
+	go.uber.org/atomic v1.4.0 // indirect
+	go.uber.org/multierr v1.1.0 // indirect
+	go.uber.org/zap v1.10.0
+)
diff --git a/vendor/github.com/blendle/zapdriver/go.sum b/vendor/github.com/blendle/zapdriver/go.sum
new file mode 100644
index 000000000..237b5d2e2
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/go.sum
@@ -0,0 +1,16 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
diff --git a/vendor/github.com/blendle/zapdriver/http.go b/vendor/github.com/blendle/zapdriver/http.go
new file mode 100644
index 000000000..441e58590
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/http.go
@@ -0,0 +1,160 @@
+package zapdriver
+
+// "Broker: Request timed out"
+// https://console.cloud.google.com/logs/viewer?project=bnl-blendle&minLogLevel=
+// 0&expandAll=false&timestamp=2018-05-23T22:21:56.142000000Z&customFacets=&limi
+// tCustomFacetWidth=true&dateRangeEnd=2018-05-23T22:21:52.545Z&interval=PT1H&re
+// source=container%2Fcluster_name%2Fblendle-2%2Fnamespace_id%2Fstream-
+// composition-analytic-events-
+// backfill&scrollTimestamp=2018-05-23T05:29:33.000000000Z&logName=projects
+// %2Fbnl-blendle%2Flogs%2Fstream-composition-analytic-events-
+// pipe-1&dateRangeUnbound=backwardInTime
+
+import (
+	"bytes"
+	"io"
+	"net/http"
+	"strconv"
+
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+// HTTP adds the correct Stackdriver "HTTP" field.
+//
+// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#HttpRequest
+func HTTP(req *HTTPPayload) zap.Field {
+	return zap.Object("httpRequest", req)
+}
+
+// HTTPPayload is the complete payload that can be interpreted by
+// Stackdriver as a HTTP request.
+type HTTPPayload struct {
+	// The request method. Examples: "GET", "HEAD", "PUT", "POST".
+	RequestMethod string `json:"requestMethod"`
+
+	// The scheme (http, https), the host name, the path and the query portion of
+	// the URL that was requested.
+	//
+	// Example: "http://example.com/some/info?color=red".
+	RequestURL string `json:"requestUrl"`
+
+	// The size of the HTTP request message in bytes, including the request
+	// headers and the request body.
+	RequestSize string `json:"requestSize"`
+
+	// The response code indicating the status of response.
+	//
+	// Examples: 200, 404.
+	Status int `json:"status"`
+
+	// The size of the HTTP response message sent back to the client, in bytes,
+	// including the response headers and the response body.
+	ResponseSize string `json:"responseSize"`
+
+	// The user agent sent by the client.
+	//
+	// Example: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.0.3705)".
+	UserAgent string `json:"userAgent"`
+
+	// The IP address (IPv4 or IPv6) of the client that issued the HTTP request.
+	//
+	// Examples: "192.168.1.1", "FE80::0202:B3FF:FE1E:8329".
+	RemoteIP string `json:"remoteIp"`
+
+	// The IP address (IPv4 or IPv6) of the origin server that the request was
+	// sent to.
+	ServerIP string `json:"serverIp"`
+
+	// The referrer URL of the request, as defined in HTTP/1.1 Header Field
+	// Definitions.
+	Referer string `json:"referer"`
+
+	// The request processing latency on the server, from the time the request was
+	// received until the response was sent.
+	//
+	// A duration in seconds with up to nine fractional digits, terminated by 's'.
+	//
+	// Example: "3.5s".
+	Latency string `json:"latency"`
+
+	// Whether or not a cache lookup was attempted.
+	CacheLookup bool `json:"cacheLookup"`
+
+	// Whether or not an entity was served from cache (with or without
+	// validation).
+	CacheHit bool `json:"cacheHit"`
+
+	// Whether or not the response was validated with the origin server before
+	// being served from cache. This field is only meaningful if cacheHit is True.
+	CacheValidatedWithOriginServer bool `json:"cacheValidatedWithOriginServer"`
+
+	// The number of HTTP response bytes inserted into cache. Set only when a
+	// cache fill was attempted.
+	CacheFillBytes string `json:"cacheFillBytes"`
+
+	// Protocol used for the request.
+	//
+	// Examples: "HTTP/1.1", "HTTP/2", "websocket"
+	Protocol string `json:"protocol"`
+}
+
+// NewHTTP returns a new HTTPPayload struct, based on the passed
+// in http.Request and http.Response objects.
+func NewHTTP(req *http.Request, res *http.Response) *HTTPPayload {
+	if req == nil {
+		req = &http.Request{}
+	}
+
+	if res == nil {
+		res = &http.Response{}
+	}
+
+	sdreq := &HTTPPayload{
+		RequestMethod: req.Method,
+		Status:        res.StatusCode,
+		UserAgent:     req.UserAgent(),
+		RemoteIP:      req.RemoteAddr,
+		Referer:       req.Referer(),
+		Protocol:      req.Proto,
+	}
+
+	if req.URL != nil {
+		sdreq.RequestURL = req.URL.String()
+	}
+
+	buf := &bytes.Buffer{}
+	if req.Body != nil {
+		n, _ := io.Copy(buf, req.Body) // nolint: gas
+		sdreq.RequestSize = strconv.FormatInt(n, 10)
+	}
+
+	if res.Body != nil {
+		buf.Reset()
+		n, _ := io.Copy(buf, res.Body) // nolint: gas
+		sdreq.ResponseSize = strconv.FormatInt(n, 10)
+	}
+
+	return sdreq
+}
+
+// MarshalLogObject implements zapcore.ObjectMarshaller interface.
+func (req HTTPPayload) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+	enc.AddString("requestMethod", req.RequestMethod)
+	enc.AddString("requestUrl", req.RequestURL)
+	enc.AddString("requestSize", req.RequestSize)
+	enc.AddInt("status", req.Status)
+	enc.AddString("responseSize", req.ResponseSize)
+	enc.AddString("userAgent", req.UserAgent)
+	enc.AddString("remoteIp", req.RemoteIP)
+	enc.AddString("serverIp", req.ServerIP)
+	enc.AddString("referer", req.Referer)
+	enc.AddString("latency", req.Latency)
+	enc.AddBool("cacheLookup", req.CacheLookup)
+	enc.AddBool("cacheHit", req.CacheHit)
+	enc.AddBool("cacheValidatedWithOriginServer", req.CacheValidatedWithOriginServer)
+	enc.AddString("cacheFillBytes", req.CacheFillBytes)
+	enc.AddString("protocol", req.Protocol)
+
+	return nil
+}
diff --git a/vendor/github.com/blendle/zapdriver/label.go b/vendor/github.com/blendle/zapdriver/label.go
new file mode 100644
index 000000000..723864209
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/label.go
@@ -0,0 +1,77 @@
+package zapdriver
+
+import (
+	"strings"
+	"sync"
+
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+const labelsKey = "logging.googleapis.com/labels"
+
+// Label adds an optional label to the payload.
+//
+// Labels are a set of user-defined (key, value) data that provides additional
+// information about the log entry.
+//
+// Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.
+func Label(key, value string) zap.Field {
+	return zap.String("labels."+key, value)
+}
+
+// Labels takes Zap fields, filters the ones that have their key start with the
+// string `labels.` and their value type set to StringType. It then wraps those
+// key/value pairs in a top-level `labels` namespace.
+func Labels(fields ...zap.Field) zap.Field {
+	lbls := newLabels()
+
+	lbls.mutex.Lock()
+	for i := range fields {
+		if isLabelField(fields[i]) {
+			lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String
+		}
+	}
+	lbls.mutex.Unlock()
+
+	return labelsField(lbls)
+}
+
+func isLabelField(field zap.Field) bool {
+	return strings.HasPrefix(field.Key, "labels.") && field.Type == zapcore.StringType
+}
+
+func labelsField(l *labels) zap.Field {
+	return zap.Object(labelsKey, l)
+}
+
+type labels struct {
+	store map[string]string
+	mutex *sync.RWMutex
+}
+
+func newLabels() *labels {
+	return &labels{store: map[string]string{}, mutex: &sync.RWMutex{}}
+}
+
+func (l *labels) Add(key, value string) {
+	l.mutex.Lock()
+	l.store[key] = value
+	l.mutex.Unlock()
+}
+
+func (l *labels) reset() {
+	l.mutex.Lock()
+	l.store = map[string]string{}
+	l.mutex.Unlock()
+}
+
+func (l labels) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+	l.mutex.RLock()
+	for k, v := range l.store {
+		enc.AddString(k, v)
+	}
+	l.mutex.RUnlock()
+
+	return nil
+}
diff --git a/vendor/github.com/blendle/zapdriver/logger.go b/vendor/github.com/blendle/zapdriver/logger.go
new file mode 100644
index 000000000..59c10993e
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/logger.go
@@ -0,0 +1,39 @@
+package zapdriver
+
+import (
+	"go.uber.org/zap"
+)
+
+// NewProduction builds a sensible production Logger that writes InfoLevel and
+// above logs to standard error as JSON.
+//
+// It's a shortcut for NewProductionConfig().Build(...Option).
+func NewProduction(options ...zap.Option) (*zap.Logger, error) {
+	options = append(options, WrapCore())
+
+	return NewProductionConfig().Build(options...)
+}
+
+// NewProductionWithCore is same as NewProduction but accepts a custom configured core
+func NewProductionWithCore(core zap.Option, options ...zap.Option) (*zap.Logger, error) {
+	options = append(options, core)
+
+	return NewProductionConfig().Build(options...)
+}
+
+// NewDevelopment builds a development Logger that writes DebugLevel and above
+// logs to standard error in a human-friendly format.
+//
+// It's a shortcut for NewDevelopmentConfig().Build(...Option).
+func NewDevelopment(options ...zap.Option) (*zap.Logger, error) {
+	options = append(options, WrapCore())
+
+	return NewDevelopmentConfig().Build(options...)
+}
+
+// NewDevelopmentWithCore is same as NewDevelopment but accepts a custom configured core
+func NewDevelopmentWithCore(core zap.Option, options ...zap.Option) (*zap.Logger, error) {
+	options = append(options, core)
+
+	return NewDevelopmentConfig().Build(options...)
+}
diff --git a/vendor/github.com/blendle/zapdriver/operation.go b/vendor/github.com/blendle/zapdriver/operation.go
new file mode 100644
index 000000000..e8b862f79
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/operation.go
@@ -0,0 +1,72 @@
+package zapdriver
+
+import (
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+const operationKey = "logging.googleapis.com/operation"
+
+// Operation adds the correct Stackdriver "operation" field.
+//
+// Additional information about a potentially long-running operation with which
+// a log entry is associated.
+//
+// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogEntryOperation
+func Operation(id, producer string, first, last bool) zap.Field {
+	op := &operation{
+		ID:       id,
+		Producer: producer,
+		First:    first,
+		Last:     last,
+	}
+
+	return zap.Object(operationKey, op)
+}
+
+// OperationStart is a convenience function for `Operation`. It should be called
+// for the first operation log.
+func OperationStart(id, producer string) zap.Field {
+	return Operation(id, producer, true, false)
+}
+
+// OperationCont is a convenience function for `Operation`. It should be called
+// for any non-start/end operation log.
+func OperationCont(id, producer string) zap.Field {
+	return Operation(id, producer, false, false)
+}
+
+// OperationEnd is a convenience function for `Operation`. It should be called
+// for the last operation log.
+func OperationEnd(id, producer string) zap.Field {
+	return Operation(id, producer, false, true)
+}
+
+// operation is the complete payload that can be interpreted by Stackdriver as
+// an operation.
+type operation struct {
+	// Optional. An arbitrary operation identifier. Log entries with the same
+	// identifier are assumed to be part of the same operation.
+	ID string `json:"id"`
+
+	// Optional. An arbitrary producer identifier. The combination of id and
+	// producer must be globally unique. Examples for producer:
+	// "MyDivision.MyBigCompany.com", "github.com/MyProject/MyApplication".
+	Producer string `json:"producer"`
+
+	// Optional. Set this to True if this is the first log entry in the operation.
+	First bool `json:"first"`
+
+	// Optional. Set this to True if this is the last log entry in the operation.
+	Last bool `json:"last"`
+}
+
+// MarshalLogObject implements zapcore.ObjectMarshaller interface.
+func (op operation) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+	enc.AddString("id", op.ID)
+	enc.AddString("producer", op.Producer)
+	enc.AddBool("first", op.First)
+	enc.AddBool("last", op.Last)
+
+	return nil
+}
diff --git a/vendor/github.com/blendle/zapdriver/report.go b/vendor/github.com/blendle/zapdriver/report.go
new file mode 100644
index 000000000..1bb8ac761
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/report.go
@@ -0,0 +1,70 @@
+package zapdriver
+
+import (
+	"runtime"
+	"strconv"
+
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+const contextKey = "context"
+
+// ErrorReport adds the correct Stackdriver "context" field for getting the log line
+// reported as error.
+//
+// see: https://cloud.google.com/error-reporting/docs/formatting-error-messages
+func ErrorReport(pc uintptr, file string, line int, ok bool) zap.Field {
+	return zap.Object(contextKey, newReportContext(pc, file, line, ok))
+}
+
+// reportLocation is the source code location information associated with the log entry
+// for the purpose of reporting an error,
+// if any.
+type reportLocation struct {
+	File     string `json:"filePath"`
+	Line     string `json:"lineNumber"`
+	Function string `json:"functionName"`
+}
+
+// MarshalLogObject implements zapcore.ObjectMarshaller interface.
+func (location reportLocation) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+	enc.AddString("filePath", location.File)
+	enc.AddString("lineNumber", location.Line)
+	enc.AddString("functionName", location.Function)
+
+	return nil
+}
+
+// reportContext is the context information attached to a log for reporting errors
+type reportContext struct {
+	ReportLocation reportLocation `json:"reportLocation"`
+}
+
+// MarshalLogObject implements zapcore.ObjectMarshaller interface.
+func (context reportContext) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+	enc.AddObject("reportLocation", context.ReportLocation)
+
+	return nil
+}
+
+func newReportContext(pc uintptr, file string, line int, ok bool) *reportContext {
+	if !ok {
+		return nil
+	}
+
+	var function string
+	if fn := runtime.FuncForPC(pc); fn != nil {
+		function = fn.Name()
+	}
+
+	context := &reportContext{
+		ReportLocation: reportLocation{
+			File:     file,
+			Line:     strconv.Itoa(line),
+			Function: function,
+		},
+	}
+
+	return context
+}
diff --git a/vendor/github.com/blendle/zapdriver/service.go b/vendor/github.com/blendle/zapdriver/service.go
new file mode 100644
index 000000000..134ff3634
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/service.go
@@ -0,0 +1,36 @@
+package zapdriver
+
+import (
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+const serviceContextKey = "serviceContext"
+
+// ServiceContext adds the correct service information adding the log line
+// It is a required field if an error needs to be reported.
+//
+// see: https://cloud.google.com/error-reporting/reference/rest/v1beta1/ServiceContext
+// see: https://cloud.google.com/error-reporting/docs/formatting-error-messages
+func ServiceContext(name string) zap.Field {
+	return zap.Object(serviceContextKey, newServiceContext(name))
+}
+
+// serviceContext describes a running service that sends errors.
+// Currently it only describes a service name.
+type serviceContext struct {
+	Name string `json:"service"`
+}
+
+// MarshalLogObject implements zapcore.ObjectMarshaller interface.
+func (service_context serviceContext) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+	enc.AddString("service", service_context.Name)
+
+	return nil
+}
+
+func newServiceContext(name string) *serviceContext {
+	return &serviceContext{
+		Name: name,
+	}
+}
diff --git a/vendor/github.com/blendle/zapdriver/source.go b/vendor/github.com/blendle/zapdriver/source.go
new file mode 100644
index 000000000..ff5ecf765
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/source.go
@@ -0,0 +1,66 @@
+package zapdriver
+
+import (
+	"runtime"
+	"strconv"
+
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+const sourceKey = "logging.googleapis.com/sourceLocation"
+
+// SourceLocation adds the correct Stackdriver "SourceLocation" field.
+//
+// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogEntrySourceLocation
+func SourceLocation(pc uintptr, file string, line int, ok bool) zap.Field {
+	return zap.Object(sourceKey, newSource(pc, file, line, ok))
+}
+
+// source is the source code location information associated with the log entry,
+// if any.
+type source struct {
+	// Optional. Source file name. Depending on the runtime environment, this
+	// might be a simple name or a fully-qualified name.
+	File string `json:"file"`
+
+	// Optional. Line within the source file. 1-based; 0 indicates no line number
+	// available.
+	Line string `json:"line"`
+
+	// Optional. Human-readable name of the function or method being invoked, with
+	// optional context such as the class or package name. This information may be
+	// used in contexts such as the logs viewer, where a file and line number are
+	// less meaningful.
+	//
+	// The format should be dir/package.func.
+	Function string `json:"function"`
+}
+
+// MarshalLogObject implements zapcore.ObjectMarshaller interface.
+func (source source) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+	enc.AddString("file", source.File)
+	enc.AddString("line", source.Line)
+	enc.AddString("function", source.Function)
+
+	return nil
+}
+
+func newSource(pc uintptr, file string, line int, ok bool) *source {
+	if !ok {
+		return nil
+	}
+
+	var function string
+	if fn := runtime.FuncForPC(pc); fn != nil {
+		function = fn.Name()
+	}
+
+	source := &source{
+		File:     file,
+		Line:     strconv.Itoa(line),
+		Function: function,
+	}
+
+	return source
+}
diff --git a/vendor/github.com/blendle/zapdriver/trace.go b/vendor/github.com/blendle/zapdriver/trace.go
new file mode 100644
index 000000000..7e1e2e8ab
--- /dev/null
+++ b/vendor/github.com/blendle/zapdriver/trace.go
@@ -0,0 +1,24 @@
+package zapdriver
+
+import (
+	"fmt"
+
+	"go.uber.org/zap"
+)
+
+const (
+	traceKey        = "logging.googleapis.com/trace"
+	spanKey         = "logging.googleapis.com/spanId"
+	traceSampledKey = "logging.googleapis.com/trace_sampled"
+)
+
+// TraceContext adds the correct Stackdriver "trace", "span", "trace_sampled fields
+//
+// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
+func TraceContext(trace string, spanId string, sampled bool, projectName string) []zap.Field {
+	return []zap.Field{
+		zap.String(traceKey, fmt.Sprintf("projects/%s/traces/%s", projectName, trace)),
+		zap.String(spanKey, spanId),
+		zap.Bool(traceSampledKey, sampled),
+	}
+}
diff --git a/vendor/knative.dev/pkg/network/prober/doc.go b/vendor/knative.dev/networking/pkg/prober/doc.go
similarity index 100%
rename from vendor/knative.dev/pkg/network/prober/doc.go
rename to vendor/knative.dev/networking/pkg/prober/doc.go
diff --git a/vendor/knative.dev/pkg/network/prober/prober.go b/vendor/knative.dev/networking/pkg/prober/prober.go
similarity index 99%
rename from vendor/knative.dev/pkg/network/prober/prober.go
rename to vendor/knative.dev/networking/pkg/prober/prober.go
index 74b9de406..5b97a78f5 100644
--- a/vendor/knative.dev/pkg/network/prober/prober.go
+++ b/vendor/knative.dev/networking/pkg/prober/prober.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2019 The Knative Authors
+Copyright 2020 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.
diff --git a/vendor/knative.dev/pkg/logging/config.go b/vendor/knative.dev/pkg/logging/config.go
index e1480033d..65b50395a 100644
--- a/vendor/knative.dev/pkg/logging/config.go
+++ b/vendor/knative.dev/pkg/logging/config.go
@@ -23,6 +23,7 @@ import (
 	"os"
 	"strings"
 
+	"github.com/blendle/zapdriver"
 	"go.uber.org/zap"
 	"go.uber.org/zap/zapcore"
 	corev1 "k8s.io/api/core/v1"
@@ -54,14 +55,14 @@ func NewLogger(configJSON string, levelOverride string, opts ...zap.Option) (*za
 		return enrichLoggerWithCommitID(logger), atomicLevel
 	}
 
-	loggingCfg := zap.NewProductionConfig()
+	loggingCfg := zapdriver.NewProductionConfig()
 	if levelOverride != "" {
 		if level, err := levelFromString(levelOverride); err == nil {
 			loggingCfg.Level = zap.NewAtomicLevelAt(*level)
 		}
 	}
 
-	logger, err2 := loggingCfg.Build(opts...)
+	logger, err2 := loggingCfg.Build(append(opts, zapdriver.WrapCore())...)
 	if err2 != nil {
 		panic(err2)
 	}
@@ -105,7 +106,7 @@ func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Opt
 		}
 	}
 
-	logger, err := loggingCfg.Build(opts...)
+	logger, err := loggingCfg.Build(append(opts, zapdriver.WrapCore())...)
 	if err != nil {
 		return nil, zap.AtomicLevel{}, err
 	}
@@ -116,15 +117,13 @@ func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Opt
 }
 
 func zapConfigFromJSON(configJSON string) (*zap.Config, error) {
-	if configJSON == "" {
-		return nil, errEmptyLoggerConfig
-	}
-
-	loggingCfg := &zap.Config{}
-	if err := json.Unmarshal([]byte(configJSON), loggingCfg); err != nil {
-		return nil, err
+	loggingCfg := zapdriver.NewProductionConfig()
+	if configJSON != "" {
+		if err := json.Unmarshal([]byte(configJSON), &loggingCfg); err != nil {
+			return nil, err
+		}
 	}
-	return loggingCfg, nil
+	return &loggingCfg, nil
 }
 
 // Config contains the configuration defined in the logging ConfigMap.
@@ -134,31 +133,9 @@ type Config struct {
 	LoggingLevel  map[string]zapcore.Level
 }
 
-const defaultZLC = `{
-  "level": "info",
-  "development": false,
-  "outputPaths": ["stdout"],
-  "errorOutputPaths": ["stderr"],
-  "encoding": "json",
-  "encoderConfig": {
-    "timeKey": "ts",
-    "levelKey": "level",
-    "nameKey": "logger",
-    "callerKey": "caller",
-    "messageKey": "msg",
-    "stacktraceKey": "stacktrace",
-    "lineEnding": "",
-    "levelEncoder": "",
-    "timeEncoder": "iso8601",
-    "durationEncoder": "",
-    "callerEncoder": ""
-  }
-}`
-
 func defaultConfig() *Config {
 	return &Config{
-		LoggingConfig: defaultZLC,
-		LoggingLevel:  make(map[string]zapcore.Level),
+		LoggingLevel: make(map[string]zapcore.Level),
 	}
 }
 
diff --git a/vendor/knative.dev/pkg/network/handlers/error.go b/vendor/knative.dev/pkg/network/handlers/error.go
deleted file mode 100644
index a6bd3bd03..000000000
--- a/vendor/knative.dev/pkg/network/handlers/error.go
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
-Copyright 2020 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 handlers
-
-import "knative.dev/pkg/network"
-
-// Error sets up a handler suitable for use with the ErrorHandler field on
-// httputil's reverse proxy, which logs /proc/net/sockstat data.
-var Error = network.ErrorHandler
diff --git a/vendor/modules.txt b/vendor/modules.txt
index ae2f927e9..45951769b 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -85,6 +85,8 @@ github.com/aws/aws-sdk-go/service/sts/stsiface
 github.com/beorn7/perks/quantile
 # github.com/blang/semver/v4 v4.0.0
 github.com/blang/semver/v4
+# github.com/blendle/zapdriver v1.3.1
+github.com/blendle/zapdriver
 # github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee
 github.com/c2h5oh/datasize
 # github.com/census-instrumentation/opencensus-proto v0.3.0
@@ -952,7 +954,7 @@ k8s.io/utils/buffer
 k8s.io/utils/integer
 k8s.io/utils/pointer
 k8s.io/utils/trace
-# knative.dev/caching v0.0.0-20201125150135-91fb5833c3c6
+# knative.dev/caching v0.0.0-20201204024709-8decac65dea7
 ## explicit
 knative.dev/caching/config
 knative.dev/caching/pkg/apis/caching
@@ -976,7 +978,7 @@ knative.dev/caching/pkg/client/listers/caching/v1alpha1
 # knative.dev/hack v0.0.0-20201201234937-fddbf732e450
 ## explicit
 knative.dev/hack
-# knative.dev/networking v0.0.0-20201125133435-4b21f11ccfa7
+# knative.dev/networking v0.0.0-20201203234509-4cd0793eed11
 ## explicit
 knative.dev/networking/config
 knative.dev/networking/pkg
@@ -1004,12 +1006,13 @@ knative.dev/networking/pkg/client/injection/informers/networking/v1alpha1/server
 knative.dev/networking/pkg/client/injection/reconciler/networking/v1alpha1/serverlessservice
 knative.dev/networking/pkg/client/listers/networking/v1alpha1
 knative.dev/networking/pkg/ingress
+knative.dev/networking/pkg/prober
 knative.dev/networking/test
 knative.dev/networking/test/conformance/ingress
 knative.dev/networking/test/defaultsystem
 knative.dev/networking/test/test_images/grpc-ping/proto
 knative.dev/networking/test/types
-# knative.dev/pkg v0.0.0-20201130192436-e5346d90e980
+# knative.dev/pkg v0.0.0-20201204175509-c9bac6be76ca
 ## explicit
 knative.dev/pkg/apiextensions/storageversion
 knative.dev/pkg/apiextensions/storageversion/cmd/migrate
@@ -1078,7 +1081,6 @@ knative.dev/pkg/metrics/metricstest
 knative.dev/pkg/metrics/testing
 knative.dev/pkg/network
 knative.dev/pkg/network/handlers
-knative.dev/pkg/network/prober
 knative.dev/pkg/pool
 knative.dev/pkg/profiling
 knative.dev/pkg/ptr


Test patch:
diff --git a/pkg/apis/serving/v1alpha1/domainmapping_lifecycle_test.go b/pkg/apis/serving/v1alpha1/domainmapping_lifecycle_test.go
index bbcb3ecc5..675c44836 100644
--- a/pkg/apis/serving/v1alpha1/domainmapping_lifecycle_test.go
+++ b/pkg/apis/serving/v1alpha1/domainmapping_lifecycle_test.go
@@ -71,6 +71,7 @@ func TestDomainClaimConditions(t *testing.T) {
 	dms := &DomainMappingStatus{}
 
 	dms.InitializeConditions()
+	dms.MarkTLSNotEnabled("AutoTLS not yet available for DomainMapping")
 	apistest.CheckConditionOngoing(dms, DomainMappingConditionDomainClaimed, t)
 	apistest.CheckConditionOngoing(dms, DomainMappingConditionReady, t)
 
@@ -102,6 +103,7 @@ func TestReferenceResolvedCondition(t *testing.T) {
 	dms := &DomainMappingStatus{}
 
 	dms.InitializeConditions()
+	dms.MarkTLSNotEnabled("AutoTLS not yet available for DomainMapping")
 	apistest.CheckConditionOngoing(dms, DomainMappingConditionReferenceResolved, t)
 	apistest.CheckConditionOngoing(dms, DomainMappingConditionReady, t)
 
@@ -129,10 +131,53 @@ func TestReferenceResolvedCondition(t *testing.T) {
 	apistest.CheckConditionFailed(dms, DomainMappingConditionReady, t)
 }
 
+func TestCertificateNotReady(t *testing.T) {
+	dms := &DomainMappingStatus{}
+
+	dms.InitializeConditions()
+	dms.MarkCertificateNotReady("cert pending")
+
+	apistest.CheckConditionOngoing(dms, DomainMappingConditionCertificateProvisioned, t)
+}
+
+func TestCertificateProvisionFailed(t *testing.T) {
+	dms := &DomainMappingStatus{}
+
+	dms.InitializeConditions()
+	dms.MarkCertificateProvisionFailed("cert failed")
+
+	apistest.CheckConditionFailed(dms, DomainMappingConditionCertificateProvisioned, t)
+}
+
+func TestDomainMappingNotOwnCertificate(t *testing.T) {
+	dms := &DomainMappingStatus{}
+	dms.InitializeConditions()
+	dms.MarkCertificateNotOwned("cert not owned")
+
+	apistest.CheckConditionFailed(dms, DomainMappingConditionCertificateProvisioned, t)
+}
+
+func TestDomainMappingAutoTLSNotEnabled(t *testing.T) {
+	dms := &DomainMappingStatus{}
+	dms.InitializeConditions()
+	dms.MarkTLSNotEnabled(AutoTLSNotEnabledMessage)
+
+	apistest.CheckConditionSucceeded(dms, DomainMappingConditionCertificateProvisioned, t)
+}
+
+func TestDomainMappingHTTPDowngrade(t *testing.T) {
+	dms := &DomainMappingStatus{}
+	dms.InitializeConditions()
+	dms.MarkHTTPDowngrade("downgraded to HTTP because we can't obtain cert")
+
+	apistest.CheckConditionSucceeded(dms, DomainMappingConditionCertificateProvisioned, t)
+}
+
 func TestPropagateIngressStatus(t *testing.T) {
 	dms := &DomainMappingStatus{}
 
 	dms.InitializeConditions()
+	dms.MarkTLSNotEnabled("AutoTLS not yet available for DomainMapping")
 	apistest.CheckConditionOngoing(dms, DomainMappingConditionIngressReady, t)
 	apistest.CheckConditionOngoing(dms, DomainMappingConditionReady, t)
 
diff --git a/pkg/reconciler/domainmapping/table_test.go b/pkg/reconciler/domainmapping/table_test.go
index 230ddca68..7243ae972 100644
--- a/pkg/reconciler/domainmapping/table_test.go
+++ b/pkg/reconciler/domainmapping/table_test.go
@@ -604,6 +604,7 @@ func withPropagatedStatus(status netv1alpha1.IngressStatus) domainMappingOption
 
 func withInitDomainMappingConditions(dm *v1alpha1.DomainMapping) {
 	dm.Status.InitializeConditions()
+	dm.Status.MarkTLSNotEnabled("AutoTLS for DomainMapping is not implemented")
 }
 
 func withDomainClaimNotOwned(dm *v1alpha1.DomainMapping) {
diff --git a/pkg/reconciler/route/table_test.go b/pkg/reconciler/route/table_test.go
index 3f2bcd5f1..ecc4b304b 100644
--- a/pkg/reconciler/route/table_test.go
+++ b/pkg/reconciler/route/table_test.go
@@ -381,6 +381,89 @@ func TestReconcile(t *testing.T) {
 			Eventf(corev1.EventTypeNormal, "Created", "Created placeholder service %q", "becomes-ready"),
 		},
 		Key: "default/becomes-ready",
+	}, {
+		Name: "simple route rollout when ingress becomes ready",
+		Objects: []runtime.Object{
+			Route("default", "becomes-ready", WithConfigTarget("config"),
+				WithRouteGeneration(2009), MarkIngressNotConfigured),
+			cfg("default", "config",
+				WithConfigGeneration(1), WithLatestCreated("config-00001"), WithLatestReady("config-00001")),
+			rev("default", "config", 1, MarkRevisionReady, WithRevName("config-00001")),
+			simpleReadyIngress(
+				Route("default", "becomes-ready", WithConfigTarget("config"), WithURL),
+				&traffic.Config{
+					Targets: map[string]traffic.RevisionTargets{
+						traffic.DefaultTarget: {{
+							TrafficTarget: v1.TrafficTarget{
+								ConfigurationName: "config",
+								RevisionName:      "config-00001",
+								Percent:           ptr.Int64(100),
+								LatestRevision:    ptr.Bool(true),
+							},
+						}},
+					},
+				},
+				simpleRollout("config", []traffic.RevisionRollout{{
+					RevisionName: "config-00000", Percent: 99,
+				}, {
+					RevisionName: "config-00001", Percent: 1,
+				}}, fakeCurTime.Add(-3*time.Second)),
+			),
+		},
+		WantCreates: []runtime.Object{
+			simplePlaceholderK8sService(getContext(), Route("default", "becomes-ready", WithConfigTarget("config")), ""),
+		},
+		WantUpdates: []clientgotesting.UpdateActionImpl{{
+			// ingress should be updated with the new rollout data.
+			Object: simpleReadyIngress(
+				Route("default", "becomes-ready", WithConfigTarget("config"), WithURL),
+				&traffic.Config{
+					Targets: map[string]traffic.RevisionTargets{
+						traffic.DefaultTarget: {{
+							TrafficTarget: v1.TrafficTarget{
+								ConfigurationName: "config",
+								RevisionName:      "config-00001",
+								Percent:           ptr.Int64(100),
+								LatestRevision:    ptr.Bool(true),
+							},
+						}},
+					},
+				},
+				simpleRollout("config", []traffic.RevisionRollout{{
+					RevisionName: "config-00000", Percent: 99,
+				}, {
+					RevisionName: "config-00001", Percent: 1,
+				}}, fakeCurTime.Add(-3*time.Second),
+					func(r *traffic.Rollout) {
+						// Step duration is 3s (now - (now-3s)).
+						r.Configurations[0].StepDuration = 3
+						// 120 / 3 = 40 steps. floor(100/40) = 2.
+						r.Configurations[0].StepSize = 2
+						// StepDuration is 3, and so next step is `now` + 3.
+						r.Configurations[0].NextStepTime = int(fakeCurTime.Add(3 * time.Second).UnixNano())
+					},
+				)),
+		}, {
+			Object: simpleK8sService(
+				Route("default", "becomes-ready", WithConfigTarget("config")),
+			),
+		}},
+		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
+			Object: Route("default", "becomes-ready", WithConfigTarget("config"),
+				// Populated by reconciliation when the route becomes ready.
+				WithURL, WithAddress, WithRouteConditionsAutoTLSDisabled,
+				WithRouteGeneration(2009), WithRouteObservedGeneration,
+				MarkTrafficAssigned, MarkIngressReady, WithStatusTraffic(
+					v1.TrafficTarget{
+						RevisionName:   "config-00001",
+						Percent:        ptr.Int64(100),
+						LatestRevision: ptr.Bool(true),
+					})),
+		}},
+		WantEvents: []string{
+			Eventf(corev1.EventTypeNormal, "Created", "Created placeholder service %q", "becomes-ready"),
+		},
+		Key: "default/becomes-ready",
 	}, {
 		Name: "failure creating k8s placeholder service",
 		// We induce a failure creating the placeholder service.
@@ -2603,7 +2686,10 @@ func url(s string) *apis.URL {
 	return url
 }
 
-func simpleRollout(cfg string, revs []traffic.RevisionRollout, now time.Time) IngressOption {
+type rolloutOption func(*traffic.Rollout)
+
+func simpleRollout(cfg string, revs []traffic.RevisionRollout,
+	now time.Time, ros ...rolloutOption) IngressOption {
 	return func(i *netv1alpha1.Ingress) {
 		r := &traffic.Rollout{
 			Configurations: []traffic.ConfigurationRollout{{
@@ -2613,6 +2699,9 @@ func simpleRollout(cfg string, revs []traffic.RevisionRollout, now time.Time) In
 				Revisions:         revs,
 			}},
 		}
+		for _, ro := range ros {
+			ro(r)
+		}
 		i.Annotations[networking.RolloutAnnotationKey] = func() string {
 			d, _ := json.Marshal(r)
 			return string(d)
diff --git a/pkg/reconciler/route/traffic/rollout_test.go b/pkg/reconciler/route/traffic/rollout_test.go
index 6ee8baaec..8927d5143 100644
--- a/pkg/reconciler/route/traffic/rollout_test.go
+++ b/pkg/reconciler/route/traffic/rollout_test.go
@@ -31,7 +31,7 @@ import (
 )
 
 func TestStep(t *testing.T) {
-	now := int(time.Now().UnixNano())
+	const now = 2020
 	tests := []struct {
 		name            string
 		prev, cur, want *Rollout
@@ -78,10 +78,11 @@ func TestStep(t *testing.T) {
 					RevisionName: "let-it-bleed",
 					Percent:      100,
 				}},
-				Deadline:     2006, // <- Those should be ignored.
-				LastStepTime: 2009,
+				Deadline:     2006, // <- Those should be kept.
+				NextStepTime: 2009,
 				StepDuration: 2020,
 				StartTime:    2004,
+				StepSize:     14,
 			}},
 		},
 		prev: &Rollout{
@@ -92,10 +93,6 @@ func TestStep(t *testing.T) {
 					RevisionName: "let-it-bleed",
 					Percent:      100,
 				}},
-				Deadline:     1982, // <- Those should be copied.
-				LastStepTime: 1984,
-				StepDuration: 1988,
-				StartTime:    1955,
 			}},
 		},
 		want: &Rollout{
@@ -106,10 +103,107 @@ func TestStep(t *testing.T) {
 					RevisionName: "let-it-bleed",
 					Percent:      100,
 				}},
-				Deadline:     1982,
-				LastStepTime: 1984,
-				StepDuration: 1988,
-				StartTime:    1955,
+			}},
+		},
+	}, {
+		name: "simplest, step",
+		cur: &Rollout{
+			Configurations: []ConfigurationRollout{{
+				ConfigurationName: "mick",
+				Percent:           100,
+				Revisions: []RevisionRollout{{
+					RevisionName: "let-it-bleed",
+					Percent:      100,
+				}},
+				NextStepTime: 2009,
+				StepDuration: 2020,
+				StartTime:    2004,
+				StepSize:     14,
+			}},
+		},
+		prev: &Rollout{
+			Configurations: []ConfigurationRollout{{
+				ConfigurationName: "mick",
+				Percent:           100,
+				NextStepTime:      2019,
+				StepDuration:      5,
+				StartTime:         2004,
+				StepSize:          3,
+				Revisions: []RevisionRollout{{
+					RevisionName: "their-satanic-majesties-request",
+					Percent:      95,
+				}, {
+					RevisionName: "let-it-bleed",
+					Percent:      5,
+				}},
+			}},
+		},
+		want: &Rollout{
+			Configurations: []ConfigurationRollout{{
+				ConfigurationName: "mick",
+				Percent:           100,
+				Revisions: []RevisionRollout{{
+					RevisionName: "their-satanic-majesties-request",
+					Percent:      92, // -3
+				}, {
+					RevisionName: "let-it-bleed",
+					Percent:      8, // +3
+				}},
+				NextStepTime: 2020 + 5, // now + duration.
+				StepDuration: 5,
+				StartTime:    2004,
+				StepSize:     3,
+			}},
+		},
+	}, {
+		name: "simplest, step, when stepsize=0",
+		cur: &Rollout{
+			Configurations: []ConfigurationRollout{{
+				ConfigurationName: "mick",
+				Percent:           100,
+				Revisions: []RevisionRollout{{
+					RevisionName: "let-it-bleed",
+					Percent:      100,
+				}},
+				Deadline:     2006,
+				NextStepTime: 2009,
+				StepDuration: 2020,
+				StartTime:    2004,
+				StepSize:     14,
+			}},
+		},
+		prev: &Rollout{
+			Configurations: []ConfigurationRollout{{
+				ConfigurationName: "mick",
+				Percent:           100,
+				NextStepTime:      2019, // <- Those should be reset and/or updated.
+				StartTime:         2004,
+				StepDuration:      5,
+				StepSize:          0,
+				Revisions: []RevisionRollout{{
+					RevisionName: "their-satanic-majesties-request",
+					Percent:      95,
+				}, {
+					RevisionName: "let-it-bleed",
+					Percent:      5,
+				}},
+			}},
+		},
+		want: &Rollout{
+			Configurations: []ConfigurationRollout{{
+				ConfigurationName: "mick",
+				Percent:           100,
+				Revisions: []RevisionRollout{{
+					RevisionName: "their-satanic-majesties-request",
+					Percent:      95,
+				}, {
+					RevisionName: "let-it-bleed",
+					Percent:      5,
+				}},
+				NextStepTime: 2019,
+				StartTime:    2004,
+				StepDuration: 5,
+				StepSize:     0,
 			}},
 		},
 	}, {
@@ -195,8 +289,9 @@ func TestStep(t *testing.T) {
 					Percent:      100,
 				}},
 				Deadline:     1982, // <- Those should be thrown out.
-				LastStepTime: 1984,
+				NextStepTime: 1984,
 				StepDuration: 1988,
+				StepSize:     11,
 			}},
 		},
 		want: &Rollout{
@@ -706,22 +801,58 @@ func TestObserveReady(t *testing.T) {
 	)
 	ro := Rollout{
 		Configurations: []ConfigurationRollout{{
+			Percent:           100,
 			ConfigurationName: "has-step",
 			StepDuration:      11,
 		}, {
 			ConfigurationName: "no-step-no-begin",
+			Percent:           100,
 		}, {
 			ConfigurationName: "step-begin < 1s",
 			StartTime:         200620092020,
+			Percent:           100,
 		}, {
 			ConfigurationName: "step-begin > 1s",
 			StartTime:         oldenDays,
+			Percent:           100,
+		}, {
+			ConfigurationName: "Percent not 100%",
+			StartTime:         oldenDays,
+			Percent:           50,
 		}},
 	}
 
-	want := ro
-	want.Configurations[2].StepDuration = 1
-	want.Configurations[3].StepDuration = 3 // 2.4 rounded up.
+	want := Rollout{
+		Configurations: []ConfigurationRollout{{
+			Percent:           100,
+			ConfigurationName: "has-step",
+			StepDuration:      11,
+		}, {
+			ConfigurationName: "no-step-no-begin",
+			Percent:           100,
+		}, {
+			ConfigurationName: "step-begin < 1s",
+			Percent:           100,
+			StartTime:         200620092020,
+			StepDuration:      2,
+			StepSize:          1,
+			NextStepTime:      now + int(2*time.Second),
+		}, {
+			ConfigurationName: "step-begin > 1s",
+			Percent:           100,
+			StartTime:         oldenDays,
+			StepDuration:      3,
+			StepSize:          100 / 40,
+			NextStepTime:      now + 3*int(time.Second),
+		}, {
+			ConfigurationName: "Percent not 100%",
+			Percent:           50,
+			StartTime:         oldenDays,
+			StepDuration:      3,
+			StepSize:          50 / 40,
+			NextStepTime:      now + 3*int(time.Second),
+		}},
+	}
 
 	// This works in place.
 	ro.ObserveReady(now)
@@ -981,7 +1112,7 @@ func TestJSONRoundtrip(t *testing.T) {
 			}},
 			StartTime:    1955,
 			Deadline:     2006,
-			LastStepTime: 1988,
+			NextStepTime: 1988,
 			StepDuration: 1984,
 		}, {
 			ConfigurationName: "no",
@@ -1014,3 +1145,175 @@ func TestJSONRoundtrip(t *testing.T) {
 			cmp.Diff(orig, deserialized, cmpopts.EquateEmpty()))
 	}
 }
+
+func TestStepRevisions(t *testing.T) {
+	tests := []struct {
+		name string
+		now  int
+		cfg  *ConfigurationRollout
+		want *ConfigurationRollout
+	}{{
+		name: "noop (1): too soon",
+		now:  1982,
+		cfg: &ConfigurationRollout{
+			NextStepTime: 1984,
+			StepSize:     10,
+			Revisions: []RevisionRollout{{
+				Percent: 10,
+			}, {
+				Percent: 5,
+			}, {
+				Percent: 60,
+			}},
+		},
+		want: &ConfigurationRollout{
+			NextStepTime: 1984,
+			StepSize:     10,
+			Revisions: []RevisionRollout{{
+				Percent: 10,
+			}, {
+				Percent: 5,
+			}, {
+				Percent: 60,
+			}},
+		},
+	}, {
+		name: "noop (2): done",
+		now:  1982,
+		cfg: &ConfigurationRollout{
+			NextStepTime: 1984,
+			StepDuration: 10,
+			StepSize:     10,
+			Revisions: []RevisionRollout{{
+				Percent: 10,
+			}},
+		},
+		want: &ConfigurationRollout{
+			NextStepTime: 1984,
+			StepDuration: 10,
+			StepSize:     10,
+			Revisions: []RevisionRollout{{
+				Percent: 10,
+			}},
+		},
+	}, {
+		name: "step last, exact time",
+		now:  1984,
+		cfg: &ConfigurationRollout{
+			NextStepTime: 1984,
+			StepSize:     10,
+			StepDuration: 55,
+			Percent:      90,
+			Revisions: []RevisionRollout{{
+				Percent: 30,
+			}, {
+				Percent: 60,
+			}},
+		},
+		want: &ConfigurationRollout{
+			Percent:      90,
+			NextStepTime: 1984 + 55,
+			StepDuration: 55,
+			StepSize:     10,
+			Revisions: []RevisionRollout{{
+				Percent: 20,
+			}, {
+				Percent: 70,
+			}},
+		},
+	}, {
+		name: "step last, delete some",
+		now:  1988,
+		cfg: &ConfigurationRollout{
+			Percent:      90,
+			NextStepTime: 1984,
+			StepSize:     10,
+			StepDuration: 55,
+			Revisions: []RevisionRollout{{
+				Percent: 22,
+			}, {
+				Percent: 5,
+			}, {
+				Percent: 3,
+			}, {
+				Percent: 60,
+			}},
+		},
+		want: &ConfigurationRollout{
+			Percent:      90,
+			NextStepTime: 1988 + 55,
+			StepDuration: 55,
+			StepSize:     10,
+			Revisions: []RevisionRollout{{
+				Percent: 20,
+			}, {
+				Percent: 70,
+			}},
+		},
+	}, {
+		name: "over target now",
+		now:  1988,
+		cfg: &ConfigurationRollout{
+			Percent:      15,
+			NextStepTime: 1984,
+			StepSize:     10,
+			StepDuration: 77,
+			Revisions: []RevisionRollout{{
+				Percent: 5,
+			}, {
+				Percent: 1,
+			}, {
+				Percent: 1,
+			}, {
+				Percent: 8,
+			}},
+		},
+		want: &ConfigurationRollout{
+			Percent:      15,
+			NextStepTime: 0,
+			StepDuration: 77,
+			StepSize:     10,
+			Revisions: []RevisionRollout{{
+				Percent: 15,
+			}},
+		},
+	}, {
+		name: "the very last step",
+		now:  2006,
+		cfg: &ConfigurationRollout{
+			NextStepTime: 1984,
+			Percent:      15,
+			StartTime:    1977,
+			StepDuration: 77,
+			StepSize:     8,
+			Revisions: []RevisionRollout{{
+				Percent: 5,
+			}, {
+				Percent: 1,
+			}, {
+				Percent: 1,
+			}, {
+				Percent: 8,
+			}},
+		},
+		want: &ConfigurationRollout{
+			NextStepTime: 0,
+			Percent:      15,
+			StartTime:    0,
+			StepDuration: 77,
+			StepSize:     8,
+			Revisions: []RevisionRollout{{
+				Percent: 15,
+			}},
+		},
+	}}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			stepRevisions(tc.cfg, tc.now)
+			if got, want := tc.cfg, tc.want; !cmp.Equal(got, want) {
+				t.Errorf("Incorrect revision stepping: diff(-want,+got):\n%s", cmp.Diff(want, got))
+			}
+		})
+	}
+}
diff --git a/test/config/config-logging.yaml b/test/config/config-logging.yaml
index 188368cd3..cd9239452 100644
--- a/test/config/config-logging.yaml
+++ b/test/config/config-logging.yaml
@@ -29,11 +29,11 @@ data:
       "errorOutputPaths": ["stderr"],
       "encoding": "json",
       "encoderConfig": {
-        "timeKey": "ts",
-        "levelKey": "level",
+        "timeKey": "timestamp",
+        "levelKey": "severity",
         "nameKey": "logger",
         "callerKey": "caller",
-        "messageKey": "msg",
+        "messageKey": "message",
         "stacktraceKey": "stacktrace",
         "lineEnding": "",
         "levelEncoder": "",
diff --git a/test/config/security/authorization_service.yaml b/test/config/security/authorization_service.yaml
deleted file mode 100644
index fb45c3605..000000000
--- a/test/config/security/authorization_service.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2020 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
-#
-#     https://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.
-
-apiVersion: security.istio.io/v1beta1
-kind: AuthorizationPolicy
-metadata:
-  name: deny-all
-  namespace: serving-tests
-  labels:
-    test.knative.dev/dependency: istio-sidecar
-spec:
-  {}
----
-apiVersion: security.istio.io/v1beta1
-kind: AuthorizationPolicy
-metadata:
-  name: allow-namespaces
-  namespace: serving-tests
-  labels:
-    test.knative.dev/dependency: istio-sidecar
-spec:
-  action: ALLOW
-  rules:
-  - from:
-    - source:
-       # knative-serving
-       # * This is for access to knative services from autoscaler and access via activator.
-       # istio-system
-       # * This is for access to k8s services from ingress-gateway in istio-system. e.g. conformance/ingress/*
-       # serving-tests
-       # * This is for access to k8s services from serving-tests. e.g TestVisibilitySplit
-       namespaces: ["knative-serving", "istio-system", "serving-tests"]
diff --git a/test/config/security/destinationrule.yaml b/test/config/security/destinationrule.yaml
deleted file mode 100644
index 728a57dd6..000000000
--- a/test/config/security/destinationrule.yaml
+++ /dev/null
@@ -1,39 +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
-#
-#     https://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.
-
-apiVersion: "networking.istio.io/v1alpha3"
-kind: "DestinationRule"
-metadata:
-  name: "mtls-services"
-  namespace: "serving-tests"
-  labels:
-    test.knative.dev/dependency: istio-sidecar
-spec:
-  host: "*.local"
-  trafficPolicy:
-    tls:
-      mode: ISTIO_MUTUAL
----
-apiVersion: "networking.istio.io/v1alpha3"
-kind: "DestinationRule"
-metadata:
-  name: "mtls-services"
-  namespace: "serving-tests-alt"
-  labels:
-    test.knative.dev/dependency: istio-sidecar
-spec:
-  host: "*.local"
-  trafficPolicy:
-    tls:
-      mode: ISTIO_MUTUAL
diff --git a/test/e2e-common.sh b/test/e2e-common.sh
index 2c65c7af0..e4f35aa59 100644
--- a/test/e2e-common.sh
+++ b/test/e2e-common.sh
@@ -429,9 +429,7 @@ function test_teardown() {
   local TEST_CONFIG_DIR=${TMP_DIR}/test/config
   echo ">> Removing test resources (${TEST_CONFIG_DIR}/)"
   ko delete --ignore-not-found=true --now -f ${TEST_CONFIG_DIR}/
-  if (( MESH )); then
-    ko delete --ignore-not-found=true --now -f ${TEST_CONFIG_DIR}/security/
-  fi
+
   echo ">> Ensuring test namespaces are clean"
   kubectl delete all --all --ignore-not-found --now --timeout 60s -n serving-tests
   kubectl delete --ignore-not-found --now --timeout 60s namespace serving-tests
diff --git a/third_party/cert-manager-latest/net-certmanager.yaml b/third_party/cert-manager-latest/net-certmanager.yaml
index 561c94430..4e51baf1c 100644
--- a/third_party/cert-manager-latest/net-certmanager.yaml
+++ b/third_party/cert-manager-latest/net-certmanager.yaml
@@ -18,7 +18,7 @@ metadata:
   # These are the permissions needed by the `cert-manager` `Certificate` implementation.
   name: knative-serving-certmanager
   labels:
-    serving.knative.dev/release: "v20201127-fb3b3cd"
+    serving.knative.dev/release: "v20201208-3a1ba61"
     serving.knative.dev/controller: "true"
     networking.knative.dev/certificate-provider: cert-manager
 rules:
@@ -49,7 +49,7 @@ kind: ValidatingWebhookConfiguration
 metadata:
   name: config.webhook.net-certmanager.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20201127-fb3b3cd"
+    serving.knative.dev/release: "v20201208-3a1ba61"
 webhooks:
   - admissionReviewVersions:
       - v1beta1
@@ -86,7 +86,7 @@ metadata:
   name: net-certmanager-webhook-certs
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201127-fb3b3cd"
+    serving.knative.dev/release: "v20201208-3a1ba61"
 
 ---
 # Copyright 2020 The Knative Authors
@@ -109,7 +109,7 @@ metadata:
   name: config-certmanager
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201127-fb3b3cd"
+    serving.knative.dev/release: "v20201208-3a1ba61"
     networking.knative.dev/certificate-provider: cert-manager
 data:
   _example: |
@@ -156,7 +156,7 @@ metadata:
   name: networking-certmanager
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201127-fb3b3cd"
+    serving.knative.dev/release: "v20201208-3a1ba61"
     networking.knative.dev/certificate-provider: cert-manager
 spec:
   selector:
@@ -168,14 +168,14 @@ spec:
         cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
       labels:
         app: networking-certmanager
-        serving.knative.dev/release: "v20201127-fb3b3cd"
+        serving.knative.dev/release: "v20201208-3a1ba61"
     spec:
       serviceAccountName: controller
       containers:
         - name: networking-certmanager
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/controller@sha256:0f5f99a5fe5b527d8154da27ad5bf433ba615facab4f4fae08b640a9586bf4fe
+          image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/controller@sha256:b9d86275283f61cec2a2c8d0433b3389f59742a45a47de7f2456caad4cea418b
           resources:
             requests:
               cpu: 30m
@@ -213,7 +213,7 @@ kind: Service
 metadata:
   labels:
     app: networking-certmanager
-    serving.knative.dev/release: "v20201127-fb3b3cd"
+    serving.knative.dev/release: "v20201208-3a1ba61"
     networking.knative.dev/certificate-provider: cert-manager
   name: networking-certmanager
   namespace: knative-serving
@@ -250,7 +250,7 @@ metadata:
   name: net-certmanager-webhook
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201127-fb3b3cd"
+    serving.knative.dev/release: "v20201208-3a1ba61"
 spec:
   selector:
     matchLabels:
@@ -263,14 +263,14 @@ spec:
       labels:
         app: net-certmanager-webhook
         role: net-certmanager-webhook
-        serving.knative.dev/release: "v20201127-fb3b3cd"
+        serving.knative.dev/release: "v20201208-3a1ba61"
     spec:
       serviceAccountName: controller
       containers:
         - name: webhook
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/webhook@sha256:40e5284e599c742e8cc439b15cc9ee49ef99c552c29fc2e6ed6934c0a94fa15e
+          image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/webhook@sha256:255ac94c18a903babea3161e7faf506f5113fab96cd42c564811fd1ae7be1fa3
           resources:
             requests:
               cpu: 20m
@@ -329,7 +329,7 @@ metadata:
   namespace: knative-serving
   labels:
     role: net-certmanager-webhook
-    serving.knative.dev/release: "v20201127-fb3b3cd"
+    serving.knative.dev/release: "v20201208-3a1ba61"
 spec:
   ports:
     # Define metrics and profiling for them to be accessible within service meshes.
diff --git a/third_party/contour-latest/contour.yaml b/third_party/contour-latest/contour.yaml
index 94e4b790f..5b49f8400 100644
--- a/third_party/contour-latest/contour.yaml
+++ b/third_party/contour-latest/contour.yaml
@@ -1482,7 +1482,7 @@ spec:
     spec:
       containers:
         - name: contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7f3205d7f42bfd2c9017eb3eab4a26a297ad74d1b8e4a3d2ce04c94281ec8a0f
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:4d3c13bd373148befdd226eeb99d583ad33fee2ac275d742743a9f709be07a37
           imagePullPolicy: Always
           command:
             - contour
@@ -1709,7 +1709,7 @@ spec:
             - --contour-key-file=/certs/tls.key
             - --config-path=/config/contour.yaml
           command: ["contour"]
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7f3205d7f42bfd2c9017eb3eab4a26a297ad74d1b8e4a3d2ce04c94281ec8a0f
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:4d3c13bd373148befdd226eeb99d583ad33fee2ac275d742743a9f709be07a37
           imagePullPolicy: IfNotPresent
           name: contour
           ports:
@@ -1798,7 +1798,7 @@ spec:
           args:
             - envoy
             - shutdown-manager
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7f3205d7f42bfd2c9017eb3eab4a26a297ad74d1b8e4a3d2ce04c94281ec8a0f
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:4d3c13bd373148befdd226eeb99d583ad33fee2ac275d742743a9f709be07a37
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -1875,7 +1875,7 @@ spec:
             - --envoy-key-file=/certs/tls.key
           command:
             - contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7f3205d7f42bfd2c9017eb3eab4a26a297ad74d1b8e4a3d2ce04c94281ec8a0f
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:4d3c13bd373148befdd226eeb99d583ad33fee2ac275d742743a9f709be07a37
           imagePullPolicy: IfNotPresent
           name: envoy-initconfig
           volumeMounts:
@@ -2097,7 +2097,7 @@ spec:
     spec:
       containers:
         - name: contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7f3205d7f42bfd2c9017eb3eab4a26a297ad74d1b8e4a3d2ce04c94281ec8a0f
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:4d3c13bd373148befdd226eeb99d583ad33fee2ac275d742743a9f709be07a37
           imagePullPolicy: Always
           command:
             - contour
@@ -2217,7 +2217,7 @@ spec:
             - --contour-key-file=/certs/tls.key
             - --config-path=/config/contour.yaml
           command: ["contour"]
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7f3205d7f42bfd2c9017eb3eab4a26a297ad74d1b8e4a3d2ce04c94281ec8a0f
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:4d3c13bd373148befdd226eeb99d583ad33fee2ac275d742743a9f709be07a37
           imagePullPolicy: IfNotPresent
           name: contour
           ports:
@@ -2306,7 +2306,7 @@ spec:
           args:
             - envoy
             - shutdown-manager
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7f3205d7f42bfd2c9017eb3eab4a26a297ad74d1b8e4a3d2ce04c94281ec8a0f
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:4d3c13bd373148befdd226eeb99d583ad33fee2ac275d742743a9f709be07a37
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -2383,7 +2383,7 @@ spec:
             - --envoy-key-file=/certs/tls.key
           command:
             - contour
-          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:7f3205d7f42bfd2c9017eb3eab4a26a297ad74d1b8e4a3d2ce04c94281ec8a0f
+          image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:4d3c13bd373148befdd226eeb99d583ad33fee2ac275d742743a9f709be07a37
           imagePullPolicy: IfNotPresent
           name: envoy-initconfig
           volumeMounts:
diff --git a/third_party/contour-latest/net-contour.yaml b/third_party/contour-latest/net-contour.yaml
index ff838385e..23bf5a790 100644
--- a/third_party/contour-latest/net-contour.yaml
+++ b/third_party/contour-latest/net-contour.yaml
@@ -33,7 +33,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: contour
-    serving.knative.dev/release: "v20201201-5716387a"
+    serving.knative.dev/release: "v20201204-b12ac184"
 data:
   _example: |
     ################################
@@ -103,7 +103,7 @@ spec:
         - name: controller
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:a79af5fd8c0089cafde29110bcd51ce38a153ec55cea39f0470e4cb61d924a32
+          image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:264111aa7b24595dbce9738883f668fa66f50a846ad49e3036f572d5090f8c0e
           resources:
             requests:
               cpu: 40m
diff --git a/third_party/istio-latest/net-istio.yaml b/third_party/istio-latest/net-istio.yaml
index b24ddea40..5412614a3 100644
--- a/third_party/istio-latest/net-istio.yaml
+++ b/third_party/istio-latest/net-istio.yaml
@@ -1,4 +1,4 @@
-# Generated when HEAD was 861d1ad147f4f7c0c79095447da9df8eefbf1497
+# Generated when HEAD was e87b1c73e380aa7798c73cd0a38ec32734af353a
 #
 # Copyright 2019 The Knative Authors
 #
@@ -20,7 +20,7 @@ metadata:
   # These are the permissions needed by the Istio Ingress implementation.
   name: knative-serving-istio
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     serving.knative.dev/controller: "true"
     networking.knative.dev/ingress-provider: istio
 rules:
@@ -50,7 +50,7 @@ metadata:
   name: knative-ingress-gateway
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -87,7 +87,7 @@ metadata:
   name: knative-local-gateway
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -106,7 +106,7 @@ metadata:
   name: knative-local-gateway
   namespace: istio-system
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 spec:
   type: ClusterIP
@@ -126,7 +126,7 @@ metadata:
   name: "webhook"
   namespace: "knative-serving"
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -141,7 +141,7 @@ metadata:
   name: "istio-webhook"
   namespace: "knative-serving"
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -170,7 +170,7 @@ kind: MutatingWebhookConfiguration
 metadata:
   name: webhook.istio.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 webhooks:
   - admissionReviewVersions:
@@ -206,7 +206,7 @@ kind: ValidatingWebhookConfiguration
 metadata:
   name: config.webhook.istio.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 webhooks:
   - admissionReviewVersions:
@@ -244,7 +244,7 @@ metadata:
   name: istio-webhook-certs
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 
 ---
@@ -268,7 +268,7 @@ metadata:
   name: config-istio
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 data:
   _example: |
@@ -338,7 +338,7 @@ metadata:
   name: networking-istio
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -354,14 +354,14 @@ spec:
         sidecar.istio.io/inject: "false"
       labels:
         app: networking-istio
-        serving.knative.dev/release: "v20201201-861d1ad1"
+        serving.knative.dev/release: "v20201208-e87b1c73"
     spec:
       serviceAccountName: controller
       containers:
         - name: networking-istio
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/controller@sha256:e16eb747220b1f910a4991529a88f867dc1534e099dbd7c2a7f354a3909e9479
+          image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/controller@sha256:39fde178bac6f7994fe76871fae2c294bce5971627d3874be85176b421749233
           resources:
             requests:
               cpu: 30m
@@ -418,7 +418,7 @@ metadata:
   name: istio-webhook
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -432,14 +432,14 @@ spec:
       labels:
         app: istio-webhook
         role: istio-webhook
-        serving.knative.dev/release: "v20201201-861d1ad1"
+        serving.knative.dev/release: "v20201208-e87b1c73"
     spec:
       serviceAccountName: controller
       containers:
         - name: webhook
           # This is the Go import path for the binary that is containerized
           # and substituted here.
-          image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/webhook@sha256:4f8b008593c7756c7e0fe7b58cb913e438e3688b969bce7eeeb6561916630b25
+          image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/webhook@sha256:38dd61407135120cb3a452914e566e19bdc2fd90499ed1a9f32b824efa605710
           resources:
             requests:
               cpu: 20m
@@ -493,7 +493,7 @@ metadata:
   namespace: knative-serving
   labels:
     role: istio-webhook
-    serving.knative.dev/release: "v20201201-861d1ad1"
+    serving.knative.dev/release: "v20201208-e87b1c73"
     networking.knative.dev/ingress-provider: istio
 spec:
   ports:
diff --git a/third_party/kourier-latest/kourier.yaml b/third_party/kourier-latest/kourier.yaml
index 499be2cc9..866d513c8 100644
--- a/third_party/kourier-latest/kourier.yaml
+++ b/third_party/kourier-latest/kourier.yaml
@@ -18,7 +18,7 @@ metadata:
   name: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 
 ---
 # Copyright 2020 The Knative Authors
@@ -42,7 +42,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
@@ -51,7 +51,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 rules:
   - apiGroups: [""]
     resources: ["events"]
@@ -78,7 +78,7 @@ metadata:
   name: 3scale-kourier
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: ClusterRole
@@ -110,7 +110,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 spec:
   replicas: 1
   selector:
@@ -122,7 +122,7 @@ spec:
         app: 3scale-kourier-control
     spec:
       containers:
-        - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:35d1b40644372a71e98edf812f79806d44b167d58a3368558c1405fe1ed396d0
+        - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:54167f3d5b79c5401c59e0747563940b9cf5d31f357bf8ed242d3955a2cd0b4a
           name: kourier-control
           env:
             - name: CERTS_SECRET_NAMESPACE
@@ -158,7 +158,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 spec:
   ports:
     - name: grpc-xds
@@ -191,7 +191,7 @@ metadata:
   namespace: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 spec:
   selector:
     matchLabels:
@@ -257,7 +257,7 @@ metadata:
   namespace: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 spec:
   ports:
     - name: http2
@@ -279,7 +279,7 @@ metadata:
   namespace: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 spec:
   ports:
     - name: http2
@@ -297,7 +297,7 @@ metadata:
   namespace: kourier-system
   labels:
     networking.knative.dev/ingress-provider: kourier
-    serving.knative.dev/release: "v20201201-705eb930"
+    serving.knative.dev/release: "v20201208-105c052d"
 data:
   envoy-bootstrap.yaml: |
     dynamic_resources:
diff --git a/vendor/knative.dev/pkg/test/logstream/v2/stream.go b/vendor/knative.dev/pkg/test/logstream/v2/stream.go
index eb8ce263f..815519fed 100644
--- a/vendor/knative.dev/pkg/test/logstream/v2/stream.go
+++ b/vendor/knative.dev/pkg/test/logstream/v2/stream.go
@@ -172,12 +172,12 @@ const (
 func (s *namespaceSource) handleLine(l []byte, pod string) {
 	// This holds the standard structure of our logs.
 	var line struct {
-		Level      string    `json:"level"`
-		Timestamp  time.Time `json:"ts"`
+		Level      string    `json:"severity"`
+		Timestamp  time.Time `json:"timestamp"`
 		Controller string    `json:"knative.dev/controller"`
 		Caller     string    `json:"caller"`
 		Key        string    `json:"knative.dev/key"`
-		Message    string    `json:"msg"`
+		Message    string    `json:"message"`
 		Error      string    `json:"error"`
 
 		// TODO(mattmoor): Parse out more context.
@@ -205,20 +205,27 @@ func (s *namespaceSource) handleLine(l []byte, pod string) {
 		if site == "" {
 			site = line.Caller
 		}
-		// E 15:04:05.000 webhook-699b7b668d-9smk2 [route-controller] [default/testroute-xyz] this is my message
-		msg := fmt.Sprintf("%s %s %s [%s] [%s] %s",
-			strings.ToUpper(string(line.Level[0])),
-			line.Timestamp.Format(timeFormat),
-			pod,
-			site,
-			line.Key,
-			line.Message)
-
-		if line.Error != "" {
-			msg += " err=" + line.Error
-		}
+		func() {
+			defer func() {
+				if err := recover(); err != nil {
+					logf("Invalid log format for pod %s: %s", pod, string(l))
+				}
+			}()
+			// E 15:04:05.000 webhook-699b7b668d-9smk2 [route-controller] [default/testroute-xyz] this is my message
+			msg := fmt.Sprintf("%s %s %s [%s] [%s] %s",
+				strings.ToUpper(string(line.Level[0])),
+				line.Timestamp.Format(timeFormat),
+				pod,
+				site,
+				line.Key,
+				line.Message)
+
+			if line.Error != "" {
+				msg += " err=" + line.Error
+			}
 
-		logf(msg)
+			logf(msg)
+		}()
 	}
 }