@marcel91200 / caddy Mirror · read-only / commits / d0b608af
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 13, 21:45 UTC

tracing: New OpenTelemetry module (#4361)

* opentelemetry: create a new module * fix imports * fix test * Update modules/caddyhttp/opentelemetry/README.md Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Update modules/caddyhttp/opentelemetry/README.md Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Update modules/caddyhttp/opentelemetry/README.md Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Update modules/caddyhttp/opentelemetry/tracer.go Co-authored-by: Dave Henderson <dhenderson@gmail.com> * rename error ErrUnsupportedTracesProtocol * replace spaces with tabs in the test data * Update modules/caddyhttp/opentelemetry/README.md Co-authored-by: Francis Lavoie <lavofr@gmail.com> * Update modules/caddyhttp/opentelemetry/README.md Co-authored-by: Francis Lavoie <lavofr@gmail.com> * replace spaces with tabs in the README.md * use default values for a propagation and exporter protocol * set http attributes with helper * simplify code * Cleanup modules/caddyhttp/opentelemetry/README.md Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Update link in README.md Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Update documentation in README.md Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Update link to naming spec in README.md Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Rename module from opentelemetry to tracing Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Rename span_name to span Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Rename span_name to span Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Simplify otel resource creation Co-authored-by: Dave Henderson <dhenderson@gmail.com> * handle extra attributes Co-authored-by: Dave Henderson <dhenderson@gmail.com> * update go.opentelemetry.io/otel/semconv to 1.7.0 Co-authored-by: Dave Henderson <dhenderson@gmail.com> * update go.opentelemetry.io/otel version * remove environment variable handling * always use tracecontext,baggage as propagators * extract tracer name into variable * rename OpenTelemetry to Tracing * simplify resource creation * update go.mod * rename package from opentelemetry to tracing * cleanup tests * update Caddyfile example in README.md * update README.md * fix test * fix module name in README.md * fix module name in README.md * change names in README.md and tests * order imports * remove redundant tests * Update documentation README.md Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Fix grammar Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Update comments Co-authored-by: Dave Henderson <dhenderson@gmail.com> * Update comments Co-authored-by: Dave Henderson <dhenderson@gmail.com> * update go.sum * update go.sum * Add otelhttp instrumentation, update OpenTelemetry libraries. * Use otelhttp instrumentation for instrumenting HTTP requests. This change uses context.WithValue to inject the next handler into the request context via a "nextCall" carrier struct, and pass it on to a standard Go HTTP handler returned by otelhttp.NewHandler. The underlying handler will extract the next handler from the context, call it and pass the returned error to the carrier struct. * use zap.Error() for the error log * remove README.md * update dependencies * clean up the code * change comment * move serveHTTP method from separate file * add syntax to the UnmarshalCaddyfile comment * go import the file * admin: Write proper status on invalid requests (#4569) (fix #4561) * update dependencies Co-authored-by: Dave Henderson <dhenderson@gmail.com> Co-authored-by: Francis Lavoie <lavofr@gmail.com> Co-authored-by: Vibhav Pant <vibhavp@gmail.com> Co-authored-by: Alok Naushad <alokme123@gmail.com> Co-authored-by: Cedric Ziel <cedric@cedric-ziel.com>

Andrii Kushch committed Mar 8, 2022 at 20:18 UTC d0b608af3178bc674936f4b1c6cce00591ebbf09
11 files changed +632 -2
caddyconfig/httpcaddyfile/directives.go
+2
@@ -37,6 +37,8 @@ import (
37 // The header directive goes second so that headers
38 // can be manipulated before doing redirects.
39 var directiveOrder = []string{
40 + "tracing",
41 +
42 "map",
43 "root",
44
caddytest/integration/caddyfile_adapt/tracing.txt new
+36
@@ -0,0 +1,36 @@
1 +:80 {
2 + tracing /myhandler {
3 + span my-span
4 + }
5 +}
6 +----------
7 +{
8 + "apps": {
9 + "http": {
10 + "servers": {
11 + "srv0": {
12 + "listen": [
13 + ":80"
14 + ],
15 + "routes": [
16 + {
17 + "match": [
18 + {
19 + "path": [
20 + "/myhandler"
21 + ]
22 + }
23 + ],
24 + "handle": [
25 + {
26 + "handler": "tracing",
27 + "span": "my-span"
28 + }
29 + ]
30 + }
31 + ]
32 + }
33 + }
34 + }
35 + }
36 +}
\ No newline at end of file
go.mod
+4
@@ -28,6 +28,10 @@ require (
28 github.com/tailscale/tscert v0.0.0-20220125204807-4509a5fbaf74
29 github.com/yuin/goldmark v1.4.4
30 github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
31 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0
32 + go.opentelemetry.io/otel v1.4.0
33 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0
34 + go.opentelemetry.io/otel/sdk v1.4.0
35 go.uber.org/zap v1.20.0
36 golang.org/x/crypto v0.0.0-20210915214749-c084706c2272
37 golang.org/x/net v0.0.0-20210913180222-943fd674d43e
go.sum
+45 -2
@@ -194,7 +194,10 @@ github.com/caddyserver/certmagic v0.15.4/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oi
194 github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo=
195 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
196 github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
197 +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
198 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
199 +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
200 +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
201 github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
202 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
203 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -218,7 +221,11 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
221 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
222 github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
223 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
224 +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
225 github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
226 +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
227 +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
228 +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
229 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
230 github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
231 github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
@@ -289,11 +296,14 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
296 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
297 github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
298 github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
299 +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
300 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
301 github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
302 github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE=
303 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
304 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
305 +github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
306 +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
307 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
308 github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
309 github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
@@ -330,6 +340,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
340 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
341 github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
342 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
343 +github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
344 +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
345 +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
346 +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
347 github.com/go-piv/piv-go v1.7.0/go.mod h1:ON2WvQncm7dIkCQ7kYJs+nc3V4jHGfrrJnSF8HKy7Gk=
348 github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
349 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@@ -412,8 +426,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
426 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
427 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
428 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
415 -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
429 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
430 +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
431 +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
432 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
433 github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
434 github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M=
@@ -489,6 +504,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
504 github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
505 github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
506 github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
507 +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
508 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
509 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
510 github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
@@ -1001,17 +1017,39 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
1017 go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
1018 go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
1019 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
1020 +go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0=
1021 go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
1022 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
1023 +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 h1:SLme4Porm+UwX0DdHMxlwRt7FzPSE0sys81bet2o0pU=
1024 +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0/go.mod h1:tLYsuf2v8fZreBVwp9gVMhefZlLFZaUiNVSq8QxXRII=
1025 go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
1026 +go.opentelemetry.io/otel v1.4.0 h1:7ESuKPq6zpjRaY5nvVDGiuwK7VAJ8MwkKnmNJ9whNZ4=
1027 +go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk=
1028 +go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg=
1029 go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
1030 +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.0 h1:j7AwzDdAQBJjcqayAaYbvpYeZzII7cEe5qJTu+De6UY=
1031 +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
1032 +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.0 h1:lRpP10E8oTGVmY1nVXcwelCT1Z8ca41/l5ce7AqLAss=
1033 +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.0/go.mod h1:3oS+j2WUoJVyj6/BzQN/52G17lNJDulngsOxDm1w2PY=
1034 +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0 h1:buSx4AMC/0Z232slPhicN/fU5KIlj0bMngct5pcZhkI=
1035 +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0/go.mod h1:ew1NcwkHo0QFT3uTm3m2IVZMkZdVIpbOYNPasgWwpdk=
1036 +go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk=
1037 +go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw=
1038 go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
1039 +go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1sC5kIwQ=
1040 +go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g=
1041 go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
1042 go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
1043 +go.opentelemetry.io/otel/sdk v1.4.0 h1:LJE4SW3jd4lQTESnlpQZcBhQ3oci0U2MLR5uhicfTHQ=
1044 +go.opentelemetry.io/otel/sdk v1.4.0/go.mod h1:71GJPNJh4Qju6zJuYl1CrYtXbrgfau/M9UAggqiy1UE=
1045 go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
1046 go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
1047 go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
1048 +go.opentelemetry.io/otel/trace v1.4.0 h1:4OOUrPZdVFQkbzl/JSdvGCWIdw5ONXXxzHlaLlWppmo=
1049 +go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE=
1050 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
1051 +go.opentelemetry.io/proto/otlp v0.12.0 h1:CMJ/3Wp7iOWES+CYLfnBv+DVmPbB+kmy9PJ92XvlR6c=
1052 +go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ=
1053 go.step.sm/cli-utils v0.7.0 h1:2GvY5Muid1yzp7YQbfCCS+gK3q7zlHjjLL5Z0DXz8ds=
1054 go.step.sm/cli-utils v0.7.0/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E=
1055 go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
@@ -1026,8 +1064,9 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
1064 go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
1065 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
1066 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
1029 -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
1067 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
1068 +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
1069 +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
1070 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
1071 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
1072 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -1279,6 +1318,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
1318 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1319 golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1320 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1321 +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1322 golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1323 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1324 golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1557,6 +1597,9 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
1597 google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
1598 google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
1599 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
1600 +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
1601 +google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
1602 +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
1603 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
1604 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
1605 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
modules/caddyhttp/standard/imports.go
+1
@@ -17,4 +17,5 @@ import (
17 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy/fastcgi"
18 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/rewrite"
19 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/templates"
20 + _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/tracing"
21 )
modules/caddyhttp/tracing/module.go new
+121
@@ -0,0 +1,121 @@
1 +package tracing
2 +
3 +import (
4 + "fmt"
5 + "net/http"
6 +
7 + "github.com/caddyserver/caddy/v2"
8 + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
9 + "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
10 + "github.com/caddyserver/caddy/v2/modules/caddyhttp"
11 + "go.uber.org/zap"
12 +)
13 +
14 +func init() {
15 + caddy.RegisterModule(Tracing{})
16 + httpcaddyfile.RegisterHandlerDirective("tracing", parseCaddyfile)
17 +}
18 +
19 +// Tracing implements an HTTP handler that adds support for distributed tracing,
20 +// using OpenTelemetry. This module is responsible for the injection and
21 +// propagation of the trace context. Configure this module via environment
22 +// variables (see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md).
23 +// Some values can be overwritten in the configuration file.
24 +type Tracing struct {
25 + // SpanName is a span name. It should follow the naming guidelines here:
26 + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#span
27 + SpanName string `json:"span"`
28 +
29 + // otel implements opentelemetry related logic.
30 + otel openTelemetryWrapper
31 +
32 + logger *zap.Logger
33 +}
34 +
35 +// CaddyModule returns the Caddy module information.
36 +func (Tracing) CaddyModule() caddy.ModuleInfo {
37 + return caddy.ModuleInfo{
38 + ID: "http.handlers.tracing",
39 + New: func() caddy.Module { return new(Tracing) },
40 + }
41 +}
42 +
43 +// Provision implements caddy.Provisioner.
44 +func (ot *Tracing) Provision(ctx caddy.Context) error {
45 + ot.logger = ctx.Logger(ot)
46 +
47 + var err error
48 + ot.otel, err = newOpenTelemetryWrapper(ctx, ot.SpanName)
49 +
50 + return err
51 +}
52 +
53 +// Cleanup implements caddy.CleanerUpper and closes any idle connections. It
54 +// calls Shutdown method for a trace provider https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#shutdown.
55 +func (ot *Tracing) Cleanup() error {
56 + if err := ot.otel.cleanup(ot.logger); err != nil {
57 + return fmt.Errorf("tracerProvider shutdown: %w", err)
58 + }
59 + return nil
60 +}
61 +
62 +// ServeHTTP implements caddyhttp.MiddlewareHandler.
63 +func (ot *Tracing) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
64 + return ot.otel.ServeHTTP(w, r, next)
65 +}
66 +
67 +// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
68 +//
69 +// tracing {
70 +// [span <span_name>]
71 +// }
72 +//
73 +func (ot *Tracing) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
74 + setParameter := func(d *caddyfile.Dispenser, val *string) error {
75 + if d.NextArg() {
76 + *val = d.Val()
77 + } else {
78 + return d.ArgErr()
79 + }
80 + if d.NextArg() {
81 + return d.ArgErr()
82 + }
83 + return nil
84 + }
85 +
86 + // paramsMap is a mapping between "string" parameter from the Caddyfile and its destination within the module
87 + paramsMap := map[string]*string{
88 + "span": &ot.SpanName,
89 + }
90 +
91 + for d.Next() {
92 + args := d.RemainingArgs()
93 + if len(args) > 0 {
94 + return d.ArgErr()
95 + }
96 +
97 + for d.NextBlock(0) {
98 + if dst, ok := paramsMap[d.Val()]; ok {
99 + if err := setParameter(d, dst); err != nil {
100 + return err
101 + }
102 + } else {
103 + return d.ArgErr()
104 + }
105 + }
106 + }
107 + return nil
108 +}
109 +
110 +func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
111 + var m Tracing
112 + err := m.UnmarshalCaddyfile(h.Dispenser)
113 + return &m, err
114 +}
115 +
116 +// Interface guards
117 +var (
118 + _ caddy.Provisioner = (*Tracing)(nil)
119 + _ caddyhttp.MiddlewareHandler = (*Tracing)(nil)
120 + _ caddyfile.Unmarshaler = (*Tracing)(nil)
121 +)
modules/caddyhttp/tracing/module_test.go new
+182
@@ -0,0 +1,182 @@
1 +package tracing
2 +
3 +import (
4 + "context"
5 + "errors"
6 + "net/http"
7 + "net/http/httptest"
8 + "strings"
9 + "testing"
10 +
11 + "github.com/caddyserver/caddy/v2"
12 + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
13 + "github.com/caddyserver/caddy/v2/modules/caddyhttp"
14 +)
15 +
16 +func TestTracing_UnmarshalCaddyfile(t *testing.T) {
17 + tests := []struct {
18 + name string
19 + spanName string
20 + d *caddyfile.Dispenser
21 + wantErr bool
22 + }{
23 + {
24 + name: "Full config",
25 + spanName: "my-span",
26 + d: caddyfile.NewTestDispenser(`
27 +tracing {
28 + span my-span
29 +}`),
30 + wantErr: false,
31 + },
32 + {
33 + name: "Only span name in the config",
34 + spanName: "my-span",
35 + d: caddyfile.NewTestDispenser(`
36 +tracing {
37 + span my-span
38 +}`),
39 + wantErr: false,
40 + },
41 + {
42 + name: "Empty config",
43 + d: caddyfile.NewTestDispenser(`
44 +tracing {
45 +}`),
46 + wantErr: false,
47 + },
48 + }
49 + for _, tt := range tests {
50 + t.Run(tt.name, func(t *testing.T) {
51 + ot := &Tracing{}
52 + if err := ot.UnmarshalCaddyfile(tt.d); (err != nil) != tt.wantErr {
53 + t.Errorf("UnmarshalCaddyfile() error = %v, wantErrType %v", err, tt.wantErr)
54 + }
55 +
56 + if ot.SpanName != tt.spanName {
57 + t.Errorf("UnmarshalCaddyfile() SpanName = %v, want SpanName %v", ot.SpanName, tt.spanName)
58 + }
59 + })
60 + }
61 +}
62 +
63 +func TestTracing_UnmarshalCaddyfile_Error(t *testing.T) {
64 + tests := []struct {
65 + name string
66 + d *caddyfile.Dispenser
67 + wantErr bool
68 + }{
69 + {
70 + name: "Unknown parameter",
71 + d: caddyfile.NewTestDispenser(`
72 + tracing {
73 + foo bar
74 + }`),
75 + wantErr: true,
76 + },
77 + {
78 + name: "Missed argument",
79 + d: caddyfile.NewTestDispenser(`
80 +tracing {
81 + span
82 +}`),
83 + wantErr: true,
84 + },
85 + }
86 + for _, tt := range tests {
87 + t.Run(tt.name, func(t *testing.T) {
88 + ot := &Tracing{}
89 + if err := ot.UnmarshalCaddyfile(tt.d); (err != nil) != tt.wantErr {
90 + t.Errorf("UnmarshalCaddyfile() error = %v, wantErrType %v", err, tt.wantErr)
91 + }
92 + })
93 + }
94 +}
95 +
96 +func TestTracing_ServeHTTP_Propagation_Without_Initial_Headers(t *testing.T) {
97 + ot := &Tracing{
98 + SpanName: "mySpan",
99 + }
100 +
101 + req := httptest.NewRequest("GET", "https://example.com/foo", nil)
102 + w := httptest.NewRecorder()
103 +
104 + var handler caddyhttp.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) error {
105 + traceparent := request.Header.Get("Traceparent")
106 + if traceparent == "" || strings.HasPrefix(traceparent, "00-00000000000000000000000000000000-0000000000000000") {
107 + t.Errorf("Invalid traceparent: %v", traceparent)
108 + }
109 +
110 + return nil
111 + }
112 +
113 + ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
114 + defer cancel()
115 +
116 + if err := ot.Provision(ctx); err != nil {
117 + t.Errorf("Provision error: %v", err)
118 + t.FailNow()
119 + }
120 +
121 + if err := ot.ServeHTTP(w, req, handler); err != nil {
122 + t.Errorf("ServeHTTP error: %v", err)
123 + }
124 +}
125 +
126 +func TestTracing_ServeHTTP_Propagation_With_Initial_Headers(t *testing.T) {
127 + ot := &Tracing{
128 + SpanName: "mySpan",
129 + }
130 +
131 + req := httptest.NewRequest("GET", "https://example.com/foo", nil)
132 + req.Header.Set("traceparent", "00-11111111111111111111111111111111-1111111111111111-01")
133 + w := httptest.NewRecorder()
134 +
135 + var handler caddyhttp.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) error {
136 + traceparent := request.Header.Get("Traceparent")
137 + if !strings.HasPrefix(traceparent, "00-11111111111111111111111111111111") {
138 + t.Errorf("Invalid traceparent: %v", traceparent)
139 + }
140 +
141 + return nil
142 + }
143 +
144 + ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
145 + defer cancel()
146 +
147 + if err := ot.Provision(ctx); err != nil {
148 + t.Errorf("Provision error: %v", err)
149 + t.FailNow()
150 + }
151 +
152 + if err := ot.ServeHTTP(w, req, handler); err != nil {
153 + t.Errorf("ServeHTTP error: %v", err)
154 + }
155 +}
156 +
157 +func TestTracing_ServeHTTP_Next_Error(t *testing.T) {
158 + ot := &Tracing{
159 + SpanName: "mySpan",
160 + }
161 +
162 + req := httptest.NewRequest("GET", "https://example.com/foo", nil)
163 + w := httptest.NewRecorder()
164 +
165 + expectErr := errors.New("test error")
166 +
167 + var handler caddyhttp.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) error {
168 + return expectErr
169 + }
170 +
171 + ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
172 + defer cancel()
173 +
174 + if err := ot.Provision(ctx); err != nil {
175 + t.Errorf("Provision error: %v", err)
176 + t.FailNow()
177 + }
178 +
179 + if err := ot.ServeHTTP(w, req, handler); err == nil || !errors.Is(err, expectErr) {
180 + t.Errorf("expected error, got: %v", err)
181 + }
182 +}
modules/caddyhttp/tracing/tracer.go new
+108
@@ -0,0 +1,108 @@
1 +package tracing
2 +
3 +import (
4 + "context"
5 + "fmt"
6 + "net/http"
7 +
8 + "github.com/caddyserver/caddy/v2"
9 +
10 + caddycmd "github.com/caddyserver/caddy/v2/cmd"
11 + "github.com/caddyserver/caddy/v2/modules/caddyhttp"
12 + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
13 + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
14 + "go.opentelemetry.io/otel/propagation"
15 + "go.opentelemetry.io/otel/sdk/resource"
16 + sdktrace "go.opentelemetry.io/otel/sdk/trace"
17 + semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
18 + "go.uber.org/zap"
19 +)
20 +
21 +const (
22 + webEngineName = "Caddy"
23 + defaultSpanName = "handler"
24 + nextCallCtxKey caddy.CtxKey = "nextCall"
25 +)
26 +
27 +// nextCall store the next handler, and the error value return on calling it (if any)
28 +type nextCall struct {
29 + next caddyhttp.Handler
30 + err error
31 +}
32 +
33 +// openTelemetryWrapper is responsible for the tracing injection, extraction and propagation.
34 +type openTelemetryWrapper struct {
35 + propagators propagation.TextMapPropagator
36 +
37 + handler http.Handler
38 +
39 + spanName string
40 +}
41 +
42 +// newOpenTelemetryWrapper is responsible for the openTelemetryWrapper initialization using provided configuration.
43 +func newOpenTelemetryWrapper(
44 + ctx context.Context,
45 + spanName string,
46 +) (openTelemetryWrapper, error) {
47 + if spanName == "" {
48 + spanName = defaultSpanName
49 + }
50 +
51 + ot := openTelemetryWrapper{
52 + spanName: spanName,
53 + }
54 +
55 + res, err := ot.newResource(webEngineName, caddycmd.CaddyVersion())
56 + if err != nil {
57 + return ot, fmt.Errorf("creating resource error: %w", err)
58 + }
59 +
60 + traceExporter, err := otlptracegrpc.New(ctx)
61 + if err != nil {
62 + return ot, fmt.Errorf("creating trace exporter error: %w", err)
63 + }
64 +
65 + ot.propagators = propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
66 +
67 + tracerProvider := globalTracerProvider.getTracerProvider(
68 + sdktrace.WithBatcher(traceExporter),
69 + sdktrace.WithResource(res),
70 + )
71 +
72 + ot.handler = otelhttp.NewHandler(http.HandlerFunc(ot.serveHTTP), ot.spanName, otelhttp.WithTracerProvider(tracerProvider), otelhttp.WithPropagators(ot.propagators))
73 + return ot, nil
74 +}
75 +
76 +// serveHTTP injects a tracing context and call the next handler.
77 +func (ot *openTelemetryWrapper) serveHTTP(w http.ResponseWriter, r *http.Request) {
78 + ot.propagators.Inject(r.Context(), propagation.HeaderCarrier(r.Header))
79 + next := r.Context().Value(nextCallCtxKey).(*nextCall)
80 + next.err = next.next.ServeHTTP(w, r)
81 +}
82 +
83 +// ServeHTTP propagates call to the by wrapped by `otelhttp` next handler.
84 +func (ot *openTelemetryWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
85 + n := &nextCall{
86 + next: next,
87 + err: nil,
88 + }
89 + ot.handler.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), nextCallCtxKey, n)))
90 +
91 + return n.err
92 +}
93 +
94 +// cleanup flush all remaining data and shutdown a tracerProvider
95 +func (ot *openTelemetryWrapper) cleanup(logger *zap.Logger) error {
96 + return globalTracerProvider.cleanupTracerProvider(logger)
97 +}
98 +
99 +// newResource creates a resource that describe current handler instance and merge it with a default attributes value.
100 +func (ot *openTelemetryWrapper) newResource(
101 + webEngineName,
102 + webEngineVersion string,
103 +) (*resource.Resource, error) {
104 + return resource.Merge(resource.Default(), resource.NewSchemaless(
105 + semconv.WebEngineNameKey.String(webEngineName),
106 + semconv.WebEngineVersionKey.String(webEngineVersion),
107 + ))
108 +}
modules/caddyhttp/tracing/tracer_test.go new
+27
@@ -0,0 +1,27 @@
1 +package tracing
2 +
3 +import (
4 + "context"
5 + "testing"
6 +
7 + "github.com/caddyserver/caddy/v2"
8 +)
9 +
10 +func TestOpenTelemetryWrapper_newOpenTelemetryWrapper(t *testing.T) {
11 + ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
12 + defer cancel()
13 +
14 + var otw openTelemetryWrapper
15 + var err error
16 +
17 + if otw, err = newOpenTelemetryWrapper(ctx,
18 + "",
19 + ); err != nil {
20 + t.Errorf("newOpenTelemetryWrapper() error = %v", err)
21 + t.FailNow()
22 + }
23 +
24 + if otw.propagators == nil {
25 + t.Errorf("Propagators should not be empty")
26 + }
27 +}
modules/caddyhttp/tracing/tracerprovider.go new
+63
@@ -0,0 +1,63 @@
1 +package tracing
2 +
3 +import (
4 + "context"
5 + "fmt"
6 + "sync"
7 +
8 + sdktrace "go.opentelemetry.io/otel/sdk/trace"
9 + "go.uber.org/zap"
10 +)
11 +
12 +// globalTracerProvider stores global tracer provider and is responsible for graceful shutdown when nobody is using it.
13 +var globalTracerProvider = &tracerProvider{}
14 +
15 +type tracerProvider struct {
16 + mu sync.Mutex
17 + tracerProvider *sdktrace.TracerProvider
18 + tracerProvidersCounter int
19 +}
20 +
21 +// getTracerProvider create or return an existing global TracerProvider
22 +func (t *tracerProvider) getTracerProvider(opts ...sdktrace.TracerProviderOption) *sdktrace.TracerProvider {
23 + t.mu.Lock()
24 + defer t.mu.Unlock()
25 +
26 + t.tracerProvidersCounter++
27 +
28 + if t.tracerProvider == nil {
29 + t.tracerProvider = sdktrace.NewTracerProvider(
30 + opts...,
31 + )
32 + }
33 +
34 + return t.tracerProvider
35 +}
36 +
37 +// cleanupTracerProvider gracefully shutdown a TracerProvider
38 +func (t *tracerProvider) cleanupTracerProvider(logger *zap.Logger) error {
39 + t.mu.Lock()
40 + defer t.mu.Unlock()
41 +
42 + if t.tracerProvidersCounter > 0 {
43 + t.tracerProvidersCounter--
44 + }
45 +
46 + if t.tracerProvidersCounter == 0 {
47 + if t.tracerProvider != nil {
48 + // tracerProvider.ForceFlush SHOULD be invoked according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#forceflush
49 + if err := t.tracerProvider.ForceFlush(context.Background()); err != nil {
50 + logger.Error("forcing flush", zap.Error(err))
51 + }
52 +
53 + // tracerProvider.Shutdown MUST be invoked according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#shutdown
54 + if err := t.tracerProvider.Shutdown(context.Background()); err != nil {
55 + return fmt.Errorf("tracerProvider shutdown error: %w", err)
56 + }
57 + }
58 +
59 + t.tracerProvider = nil
60 + }
61 +
62 + return nil
63 +}
modules/caddyhttp/tracing/tracerprovider_test.go new
+43
@@ -0,0 +1,43 @@
1 +package tracing
2 +
3 +import (
4 + "testing"
5 +
6 + "go.uber.org/zap"
7 +)
8 +
9 +func Test_tracersProvider_getTracerProvider(t *testing.T) {
10 + tp := tracerProvider{}
11 +
12 + tp.getTracerProvider()
13 + tp.getTracerProvider()
14 +
15 + if tp.tracerProvider == nil {
16 + t.Errorf("There should be tracer provider")
17 + }
18 +
19 + if tp.tracerProvidersCounter != 2 {
20 + t.Errorf("Tracer providers counter should equal to 2")
21 + }
22 +}
23 +
24 +func Test_tracersProvider_cleanupTracerProvider(t *testing.T) {
25 + tp := tracerProvider{}
26 +
27 + tp.getTracerProvider()
28 + tp.getTracerProvider()
29 +
30 + err := tp.cleanupTracerProvider(zap.NewNop())
31 +
32 + if err != nil {
33 + t.Errorf("There should be no error: %v", err)
34 + }
35 +
36 + if tp.tracerProvider == nil {
37 + t.Errorf("There should be tracer provider")
38 + }
39 +
40 + if tp.tracerProvidersCounter != 1 {
41 + t.Errorf("Tracer providers counter should equal to 1")
42 + }
43 +}