New Upstream Release - golang-gitlab-gitlab-org-labkit

Ready changes

Summary

Merged new upstream version: 1.20.0 (was: 1.17.0).

Diff

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e9fc3b8..9f25b2e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,5 +1,5 @@
 default:
-  image: golang:1.18
+  image: golang:1.20
   tags:
     - gitlab-org
 
@@ -19,20 +19,21 @@ variables:
 .go-version-matrix:
   parallel:
     matrix:
-      - GO_VERSION: ["1.18", "1.19"]
+      - GO_VERSION: ["1.18", "1.19", "1.20"]
 
 backwards_compat:
-  image: registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-ruby-2.7-golang-1.18:git-2.36
+  image: registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-golang-1.20-rust-1.65:git-2.36
   parallel:
     matrix:
-      - REPO:
+      - REPO_AND_DIR:
         - https://gitlab.com/gitlab-org/gitaly.git
         - https://gitlab.com/gitlab-org/container-registry.git
         - https://gitlab.com/gitlab-org/gitlab-shell.git
         - https://gitlab.com/gitlab-org/gitlab-pages.git
+        - https://gitlab.com/gitlab-org/gitlab.git workhorse
   stage: verify
   script:
-    - ./backwords_compat.sh ${REPO}
+    - ./backwards_compat.sh ${REPO_AND_DIR}
 
 stages:
   - build
diff --git a/.tool-versions b/.tool-versions
index 01a46ef..e8a8173 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,3 +1,3 @@
-golang 1.18.9
+golang 1.20.4
 # asdf plugin add golangci-lint https://github.com/hypnoglow/asdf-golangci-lint.git
 golangci-lint 1.41.1
diff --git a/backwords_compat.sh b/backwards_compat.sh
similarity index 66%
rename from backwords_compat.sh
rename to backwards_compat.sh
index 012d135..398abee 100755
--- a/backwords_compat.sh
+++ b/backwards_compat.sh
@@ -2,17 +2,27 @@
 
 set -eux
 
-repo=$1
+[ -z "${1:-}" ] && (
+	echo "INFO: Please specify a HTTPS git URL to process."
+	exit 1
+)
+
+repo=${1}
+dir=${2:-}
+
 cloneDir=$(mktemp -d)
+
 CI_PROJECT_DIR=${CI_PROJECT_DIR:-$(pwd)}
 
 git clone --depth 1 "$repo" "$cloneDir"
-cd "$cloneDir"
+cd "$cloneDir/$dir"
+
+grep -E '^go ' go.mod
 
 go mod edit -replace=gitlab.com/gitlab-org/labkit="$CI_PROJECT_DIR"
 
 # Ensure go.mod and go.sum are up to date in the cloned repo, otherwise build may fail.
-go mod tidy -compat=1.18
+go mod tidy
 
 make -j "$(nproc)"
 
diff --git a/debian/changelog b/debian/changelog
index 0c99475..fccf48a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-gitlab-gitlab-org-labkit (1.20.0-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sat, 19 Aug 2023 02:51:02 -0000
+
 golang-gitlab-gitlab-org-labkit (1.17.0-2) unstable; urgency=medium
 
   * Team upload.
diff --git a/downstream-vendor.sh b/downstream-vendor.sh
index c7fc751..517d948 100755
--- a/downstream-vendor.sh
+++ b/downstream-vendor.sh
@@ -79,7 +79,7 @@ function vendor_downstream_project() {
 
   # Update to the appropriate commit SHA
   go get -u=patch "gitlab.com/gitlab-org/labkit@$LABKIT_VERSION_TAG"
-  go mod tidy -compat=1.18
+  go mod tidy
   git add go.mod go.sum
 
   if [[ "$vendor_branch_exists" == "yes" ]]; then
diff --git a/go.mod b/go.mod
index 69094f7..f50c8b3 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
 	github.com/prometheus/client_golang v1.12.1
 	github.com/prometheus/client_model v0.2.0
 	github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
-	github.com/sirupsen/logrus v1.8.1
+	github.com/sirupsen/logrus v1.9.3
 	github.com/stretchr/testify v1.7.0
 	github.com/uber/jaeger-client-go v2.29.1+incompatible
 	go.opencensus.io v0.23.0
diff --git a/go.sum b/go.sum
index 06e4d67..6da9dff 100644
--- a/go.sum
+++ b/go.sum
@@ -315,8 +315,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
@@ -527,6 +527,7 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
diff --git a/mask/matchers.go b/mask/matchers.go
index 5caddae..96593a0 100644
--- a/mask/matchers.go
+++ b/mask/matchers.go
@@ -28,6 +28,7 @@ var parameterMatches = []string{
 	`^text$`,
 	`^title$`,
 	`^jwt$`,
+	`^redirect$`,
 }
 
 var headerMatches = []string{
diff --git a/mask/url_test.go b/mask/url_test.go
index 40737b7..b61137e 100644
--- a/mask/url_test.go
+++ b/mask/url_test.go
@@ -58,6 +58,7 @@ func TestURL(t *testing.T) {
 		"?content=e=mc2":                                                    "?content=[FILTERED]",
 		"?formula=e=mc2":                                                    "?formula=e=mc2",
 		"http://%41:8080/":                                                  "<invalid URL>",
+		"?redirect=http://example.com/":                                     "?redirect=[FILTERED]",
 		"https://gitlab.com?name=andrew&password=1&secret=1&key=1&signature=1&authorization=1&note=1&certificate=1&encrypted_key=1&hook=1&import_url=1&otp_attempt=1&sentry_dsn=1&trace=1&variables=1&content=1&sharedsecret=1&real=1": "https://gitlab.com?name=andrew&password=[FILTERED]&secret=[FILTERED]&key=[FILTERED]&signature=[FILTERED]&authorization=[FILTERED]&note=[FILTERED]&certificate=[FILTERED]&encrypted_key=[FILTERED]&hook=[FILTERED]&import_url=[FILTERED]&otp_attempt=[FILTERED]&sentry_dsn=[FILTERED]&trace=[FILTERED]&variables=[FILTERED]&content=[FILTERED]&sharedsecret=[FILTERED]&real=1", // nolint:lll
 	}
 
diff --git a/monitoring/doc.go b/monitoring/doc.go
index 96ef103..5319cbb 100644
--- a/monitoring/doc.go
+++ b/monitoring/doc.go
@@ -44,5 +44,9 @@ processes when it is enabled. This cost is only incurred when the profiler is sw
 the `GITLAB_CONTINUOUS_PROFILING`) environment variable. More details can be found at
 https://medium.com/google-cloud/continuous-profiling-of-go-programs-96d4416af77b.
 
+*How to make use of profiles*
+
+- https://youtu.be/MxGQ7WZ2N74 : A look at how one can use Go profiles in practice
+
 */
 package monitoring
diff --git a/tidy.sh b/tidy.sh
index c3b8811..ae6e238 100755
--- a/tidy.sh
+++ b/tidy.sh
@@ -4,7 +4,7 @@ set -eux
 
 # Check go tidy
 git diff go.sum go.mod > /tmp/gomod-"${CI_JOB_ID}"-before
-go mod tidy -compat=1.18
 git diff go.sum go.mod > /tmp/gomod-"${CI_JOB_ID}"-after
+go mod tidy
 diff -U0 /tmp/gomod-"${CI_JOB_ID}"-before /tmp/gomod-"${CI_JOB_ID}"-after
 
diff --git a/tracing/impl/default_sampling.go b/tracing/impl/default_sampling.go
new file mode 100644
index 0000000..afd7d7d
--- /dev/null
+++ b/tracing/impl/default_sampling.go
@@ -0,0 +1,28 @@
+package impl
+
+import (
+	"github.com/opentracing/opentracing-go"
+)
+
+var IsSampled = func(span opentracing.Span) bool {
+	spanContext := span.Context()
+
+	// Other non-exported context with conditional build tags. They must
+	// implement samplingChecker interface.
+	if spanSampler, ok := spanContext.(samplingChecker); ok {
+		return spanSampler.IsSampled()
+	}
+
+	return false
+}
+
+// samplingChecker is an interface consisting of one function that returns
+// the sampling status. Some implementations follow opentracing. Labkit doesn't
+// need to convert. Some others, such as stackdriver, implement opentracing
+// wrappers. Those wrappers are internal, and conditional built when receiving
+// corresponding build tag. As a result, such wrappers are not available for
+// casting in IsSampled function above.
+// Such implementations have to take a detour by implementing this interface.
+type samplingChecker interface {
+	IsSampled() bool
+}
diff --git a/tracing/impl/jaeger_sampling.go b/tracing/impl/jaeger_sampling.go
new file mode 100644
index 0000000..e3b8439
--- /dev/null
+++ b/tracing/impl/jaeger_sampling.go
@@ -0,0 +1,21 @@
+//go:build tracer_static && tracer_static_jaeger
+// +build tracer_static,tracer_static_jaeger
+
+package impl
+
+import (
+	"github.com/opentracing/opentracing-go"
+	"github.com/uber/jaeger-client-go"
+)
+
+func init() {
+	is := IsSampled
+	IsSampled = func(span opentracing.Span) bool {
+		spanContext := span.Context()
+
+		if jaegerContext, ok := spanContext.(jaeger.SpanContext); ok {
+			return jaegerContext.IsSampled()
+		}
+		return is(span)
+	}
+}
diff --git a/tracing/impl/jaeger_tracer_test.go b/tracing/impl/jaeger_tracer_test.go
index 8008248..b90cb6b 100644
--- a/tracing/impl/jaeger_tracer_test.go
+++ b/tracing/impl/jaeger_tracer_test.go
@@ -3,6 +3,9 @@
 package impl
 
 import (
+	"fmt"
+	"github.com/opentracing/opentracing-go"
+	"github.com/stretchr/testify/require"
 	"testing"
 
 	"gitlab.com/gitlab-org/labkit/tracing/connstr"
@@ -90,3 +93,40 @@ func TestTracerFactory(t *testing.T) {
 		})
 	}
 }
+
+func TestIsSampled_jaeger(t *testing.T) {
+	t.Parallel()
+
+	for _, tc := range []struct {
+		desc       string
+		connection string
+		sampled    bool
+	}{
+		{
+			desc:       "jaeger sampled",
+			connection: "opentracing://jaeger?sampler=probabilistic&sampler_param=1",
+			sampled:    true,
+		},
+		{
+			desc:       "jaeger not sampled",
+			connection: "opentracing://jaeger?sampler=probabilistic&sampler_param=0",
+			sampled:    false,
+		},
+	} {
+		t.Run(tc.desc, func(t *testing.T) {
+			_, options, err := connstr.Parse(tc.connection)
+			require.NoError(t, err)
+			options["service_name"] = "test"
+
+			jaegerTracer, closer, err := jaegerTracerFactory(options)
+			require.NoError(t, err)
+
+			span := jaegerTracer.StartSpan("rootSpan")
+			for i := 0; i < 10; i++ {
+				require.Equal(t, tc.sampled, IsSampled(span))
+				span = jaegerTracer.StartSpan(fmt.Sprintf("span%d", i), opentracing.ChildOf(span.Context()))
+			}
+			require.NoError(t, closer.Close())
+		})
+	}
+}
diff --git a/tracing/impl/lightstep_sampling.go b/tracing/impl/lightstep_sampling.go
new file mode 100644
index 0000000..d25568d
--- /dev/null
+++ b/tracing/impl/lightstep_sampling.go
@@ -0,0 +1,21 @@
+//go:build tracer_static && tracer_static_lightstep
+// +build tracer_static,tracer_static_lightstep
+
+package impl
+
+import (
+	"github.com/lightstep/lightstep-tracer-go"
+	"github.com/opentracing/opentracing-go"
+)
+
+func init() {
+	is := IsSampled
+	IsSampled = func(span opentracing.Span) bool {
+		spanContext := span.Context()
+
+		if lightstepContext, ok := spanContext.(lightstep.SpanContext); ok {
+			return lightstepContext.Sampled == "true"
+		}
+		return is(span)
+	}
+}
diff --git a/tracing/impl/lightstep_tracer_test.go b/tracing/impl/lightstep_tracer_test.go
index c4750d5..3460bed 100644
--- a/tracing/impl/lightstep_tracer_test.go
+++ b/tracing/impl/lightstep_tracer_test.go
@@ -3,6 +3,10 @@
 package impl
 
 import (
+	"fmt"
+	"github.com/lightstep/lightstep-tracer-go"
+	"github.com/opentracing/opentracing-go"
+	"github.com/stretchr/testify/require"
 	"testing"
 
 	"gitlab.com/gitlab-org/labkit/tracing/connstr"
@@ -65,3 +69,47 @@ func Test_lightstepTracerFactory(t *testing.T) {
 		})
 	}
 }
+
+func TestIsSampled_lightstep(t *testing.T) {
+	t.Parallel()
+
+	for _, tc := range []struct {
+		desc       string
+		connection string
+		sampled    bool
+	}{
+		{
+			desc:       "lightstep sampled",
+			connection: "opentracing://lightstep?access_token=12345&relaxed",
+			sampled:    true,
+		},
+		{
+			desc:       "lightstep not sampled",
+			connection: "opentracing://lightstep?access_token=12345&relaxed",
+			sampled:    false,
+		},
+	} {
+		t.Run(tc.desc, func(t *testing.T) {
+			_, options, err := connstr.Parse(tc.connection)
+			require.NoError(t, err)
+			options["service_name"] = "test"
+
+			lightstepTracer, closer, err := lightstepTracerFactory(options)
+			require.NoError(t, err)
+
+			var opt opentracing.StartSpanOption
+			if tc.sampled {
+				opt = lightstep.SetSampled("true")
+			} else {
+				opt = lightstep.SetSampled("false")
+			}
+
+			span := lightstepTracer.StartSpan("rootSpan", lightstep.SetTraceID(1), opt)
+			for i := 0; i < 10; i++ {
+				require.Equal(t, tc.sampled, IsSampled(span))
+				span = lightstepTracer.StartSpan(fmt.Sprintf("span%d", i), opentracing.ChildOf(span.Context()))
+			}
+			require.NoError(t, closer.Close())
+		})
+	}
+}
diff --git a/tracing/impl/stackdriver_tracer.go b/tracing/impl/stackdriver_tracer.go
index c6ba142..1031880 100644
--- a/tracing/impl/stackdriver_tracer.go
+++ b/tracing/impl/stackdriver_tracer.go
@@ -58,7 +58,8 @@ func (tracer *adapterTracer) StartSpan(operationName string, opts ...opentracing
 		ctx, span = trace.StartSpan(ctx, operationName)
 	}
 
-	adapterSpan := &adapterSpan{span, tracer, adapterSpanContext{ctx, false, nil}}
+	spanContext := span.SpanContext()
+	adapterSpan := &adapterSpan{span, tracer, adapterSpanContext{ctx, false, &spanContext}}
 	for k, v := range sso.Tags {
 		adapterSpan.SetTag(k, v)
 	}
@@ -120,6 +121,9 @@ type adapterSpanContext struct {
 }
 
 func (c adapterSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {}
+func (c adapterSpanContext) IsSampled() bool {
+	return c.ocSpanCtx.IsSampled()
+}
 
 // https://pkg.go.dev/go.opencensus.io/trace#Span
 // https://pkg.go.dev/github.com/opentracing/opentracing-go#Span
diff --git a/tracing/impl/stackdriver_tracer_test.go b/tracing/impl/stackdriver_tracer_test.go
index 91cf249..db55a08 100644
--- a/tracing/impl/stackdriver_tracer_test.go
+++ b/tracing/impl/stackdriver_tracer_test.go
@@ -1,8 +1,11 @@
-// +build tracer_static,tracer_static_jaeger
+// +build tracer_static,tracer_static_stackdriver
 
 package impl
 
 import (
+	"fmt"
+	"github.com/opentracing/opentracing-go"
+	"github.com/stretchr/testify/require"
 	"reflect"
 	"strings"
 	"testing"
@@ -129,3 +132,35 @@ func TestOcSpanAdapterCastToAttribute(t *testing.T) {
 		})
 	}
 }
+func TestIsSampled_stackdriver(t *testing.T) {
+	t.Parallel()
+
+	for _, tc := range []struct {
+		desc    string
+		sampled bool
+	}{
+		{
+			desc:    "stackdriver sampled",
+			sampled: true,
+		},
+		{
+			desc:    "stackdriver not sampled",
+			sampled: false,
+		},
+	} {
+		t.Run(tc.desc, func(t *testing.T) {
+			stackdriverTracer := &adapterTracer{nil}
+			if tc.sampled {
+				trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
+			} else {
+				trace.ApplyConfig(trace.Config{DefaultSampler: trace.NeverSample()})
+			}
+
+			span := stackdriverTracer.StartSpan("rootSpan")
+			for i := 0; i < 10; i++ {
+				require.Equal(t, tc.sampled, IsSampled(span))
+				span = stackdriverTracer.StartSpan(fmt.Sprintf("span%d", i), opentracing.ChildOf(span.Context()))
+			}
+		})
+	}
+}
diff --git a/tracing/sampling.go b/tracing/sampling.go
new file mode 100644
index 0000000..edf2680
--- /dev/null
+++ b/tracing/sampling.go
@@ -0,0 +1,25 @@
+package tracing
+
+import (
+	"github.com/opentracing/opentracing-go"
+	"gitlab.com/gitlab-org/labkit/tracing/impl"
+)
+
+// IsSampled returns the sampling status (true/false) of a span. This function
+// wraps around the actual implementation in `impl` packet. Technically, we don't
+// need this wrapper, but the `impl` package contains detailed implementation.
+// Most consumers import `gitlab.com/gitlab-org/labkit/tracing`
+func IsSampled(span opentracing.Span) bool {
+	// IsSampled returns the sampling status (true/false) of a span. Most
+	// implementations support checking this status. Unfortunately, we hide the
+	// tracing implementations behind unified opentracing interfaces. The single
+	// input is an opentracing.Span interface. As a result, we need to type-cast it
+	// back to all supported implementations.
+	// This status is particularly useful when a span is not free to collect, or
+	// has to turn on some special configs. One example is Git Trace2. It's a
+	// built-in observability tool that provides a deeper look into Git processes.
+	// Enabling this feature is not expensive, but not cheap either. We don't want
+	// to enable it for all Git processes. So, it makes sense to collect such data
+	// when the parent span is sampled.
+	return impl.IsSampled(span)
+}

More details

Full run details

Historical runs