mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-16 21:56:40 -05:00
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>
This commit is contained in:
parent
d9b1d46325
commit
d0b608af31
11 changed files with 632 additions and 2 deletions
|
@ -37,6 +37,8 @@ import (
|
|||
// The header directive goes second so that headers
|
||||
// can be manipulated before doing redirects.
|
||||
var directiveOrder = []string{
|
||||
"tracing",
|
||||
|
||||
"map",
|
||||
"root",
|
||||
|
||||
|
|
36
caddytest/integration/caddyfile_adapt/tracing.txt
Normal file
36
caddytest/integration/caddyfile_adapt/tracing.txt
Normal file
|
@ -0,0 +1,36 @@
|
|||
:80 {
|
||||
tracing /myhandler {
|
||||
span my-span
|
||||
}
|
||||
}
|
||||
----------
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"srv0": {
|
||||
"listen": [
|
||||
":80"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"path": [
|
||||
"/myhandler"
|
||||
]
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "tracing",
|
||||
"span": "my-span"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
go.mod
4
go.mod
|
@ -28,6 +28,10 @@ require (
|
|||
github.com/tailscale/tscert v0.0.0-20220125204807-4509a5fbaf74
|
||||
github.com/yuin/goldmark v1.4.4
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0
|
||||
go.opentelemetry.io/otel v1.4.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0
|
||||
go.opentelemetry.io/otel/sdk v1.4.0
|
||||
go.uber.org/zap v1.20.0
|
||||
golang.org/x/crypto v0.0.0-20210915214749-c084706c2272
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e
|
||||
|
|
47
go.sum
47
go.sum
|
@ -194,7 +194,10 @@ github.com/caddyserver/certmagic v0.15.4/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oi
|
|||
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
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
|
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
||||
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
|
|||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
|
||||
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
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
|
|||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-piv/piv-go v1.7.0/go.mod h1:ON2WvQncm7dIkCQ7kYJs+nc3V4jHGfrrJnSF8HKy7Gk=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
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/
|
|||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||
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
|
|||
github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
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=
|
|||
go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0=
|
||||
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 h1:SLme4Porm+UwX0DdHMxlwRt7FzPSE0sys81bet2o0pU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0/go.mod h1:tLYsuf2v8fZreBVwp9gVMhefZlLFZaUiNVSq8QxXRII=
|
||||
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
|
||||
go.opentelemetry.io/otel v1.4.0 h1:7ESuKPq6zpjRaY5nvVDGiuwK7VAJ8MwkKnmNJ9whNZ4=
|
||||
go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk=
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg=
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.0 h1:j7AwzDdAQBJjcqayAaYbvpYeZzII7cEe5qJTu+De6UY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.0 h1:lRpP10E8oTGVmY1nVXcwelCT1Z8ca41/l5ce7AqLAss=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.0/go.mod h1:3oS+j2WUoJVyj6/BzQN/52G17lNJDulngsOxDm1w2PY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0 h1:buSx4AMC/0Z232slPhicN/fU5KIlj0bMngct5pcZhkI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.0/go.mod h1:ew1NcwkHo0QFT3uTm3m2IVZMkZdVIpbOYNPasgWwpdk=
|
||||
go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk=
|
||||
go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw=
|
||||
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
|
||||
go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1sC5kIwQ=
|
||||
go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g=
|
||||
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
|
||||
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
|
||||
go.opentelemetry.io/otel/sdk v1.4.0 h1:LJE4SW3jd4lQTESnlpQZcBhQ3oci0U2MLR5uhicfTHQ=
|
||||
go.opentelemetry.io/otel/sdk v1.4.0/go.mod h1:71GJPNJh4Qju6zJuYl1CrYtXbrgfau/M9UAggqiy1UE=
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
|
||||
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||
go.opentelemetry.io/otel/trace v1.4.0 h1:4OOUrPZdVFQkbzl/JSdvGCWIdw5ONXXxzHlaLlWppmo=
|
||||
go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.12.0 h1:CMJ/3Wp7iOWES+CYLfnBv+DVmPbB+kmy9PJ92XvlR6c=
|
||||
go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ=
|
||||
go.step.sm/cli-utils v0.7.0 h1:2GvY5Muid1yzp7YQbfCCS+gK3q7zlHjjLL5Z0DXz8ds=
|
||||
go.step.sm/cli-utils v0.7.0/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E=
|
||||
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=
|
|||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
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
|
|||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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
|
|||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
|
|
|
@ -17,4 +17,5 @@ import (
|
|||
_ "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy/fastcgi"
|
||||
_ "github.com/caddyserver/caddy/v2/modules/caddyhttp/rewrite"
|
||||
_ "github.com/caddyserver/caddy/v2/modules/caddyhttp/templates"
|
||||
_ "github.com/caddyserver/caddy/v2/modules/caddyhttp/tracing"
|
||||
)
|
||||
|
|
121
modules/caddyhttp/tracing/module.go
Normal file
121
modules/caddyhttp/tracing/module.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package tracing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(Tracing{})
|
||||
httpcaddyfile.RegisterHandlerDirective("tracing", parseCaddyfile)
|
||||
}
|
||||
|
||||
// Tracing implements an HTTP handler that adds support for distributed tracing,
|
||||
// using OpenTelemetry. This module is responsible for the injection and
|
||||
// propagation of the trace context. Configure this module via environment
|
||||
// variables (see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md).
|
||||
// Some values can be overwritten in the configuration file.
|
||||
type Tracing struct {
|
||||
// SpanName is a span name. It should follow the naming guidelines here:
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#span
|
||||
SpanName string `json:"span"`
|
||||
|
||||
// otel implements opentelemetry related logic.
|
||||
otel openTelemetryWrapper
|
||||
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
func (Tracing) CaddyModule() caddy.ModuleInfo {
|
||||
return caddy.ModuleInfo{
|
||||
ID: "http.handlers.tracing",
|
||||
New: func() caddy.Module { return new(Tracing) },
|
||||
}
|
||||
}
|
||||
|
||||
// Provision implements caddy.Provisioner.
|
||||
func (ot *Tracing) Provision(ctx caddy.Context) error {
|
||||
ot.logger = ctx.Logger(ot)
|
||||
|
||||
var err error
|
||||
ot.otel, err = newOpenTelemetryWrapper(ctx, ot.SpanName)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Cleanup implements caddy.CleanerUpper and closes any idle connections. It
|
||||
// calls Shutdown method for a trace provider https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#shutdown.
|
||||
func (ot *Tracing) Cleanup() error {
|
||||
if err := ot.otel.cleanup(ot.logger); err != nil {
|
||||
return fmt.Errorf("tracerProvider shutdown: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeHTTP implements caddyhttp.MiddlewareHandler.
|
||||
func (ot *Tracing) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
|
||||
return ot.otel.ServeHTTP(w, r, next)
|
||||
}
|
||||
|
||||
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
|
||||
//
|
||||
// tracing {
|
||||
// [span <span_name>]
|
||||
// }
|
||||
//
|
||||
func (ot *Tracing) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
setParameter := func(d *caddyfile.Dispenser, val *string) error {
|
||||
if d.NextArg() {
|
||||
*val = d.Val()
|
||||
} else {
|
||||
return d.ArgErr()
|
||||
}
|
||||
if d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// paramsMap is a mapping between "string" parameter from the Caddyfile and its destination within the module
|
||||
paramsMap := map[string]*string{
|
||||
"span": &ot.SpanName,
|
||||
}
|
||||
|
||||
for d.Next() {
|
||||
args := d.RemainingArgs()
|
||||
if len(args) > 0 {
|
||||
return d.ArgErr()
|
||||
}
|
||||
|
||||
for d.NextBlock(0) {
|
||||
if dst, ok := paramsMap[d.Val()]; ok {
|
||||
if err := setParameter(d, dst); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return d.ArgErr()
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||
var m Tracing
|
||||
err := m.UnmarshalCaddyfile(h.Dispenser)
|
||||
return &m, err
|
||||
}
|
||||
|
||||
// Interface guards
|
||||
var (
|
||||
_ caddy.Provisioner = (*Tracing)(nil)
|
||||
_ caddyhttp.MiddlewareHandler = (*Tracing)(nil)
|
||||
_ caddyfile.Unmarshaler = (*Tracing)(nil)
|
||||
)
|
182
modules/caddyhttp/tracing/module_test.go
Normal file
182
modules/caddyhttp/tracing/module_test.go
Normal file
|
@ -0,0 +1,182 @@
|
|||
package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
)
|
||||
|
||||
func TestTracing_UnmarshalCaddyfile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
spanName string
|
||||
d *caddyfile.Dispenser
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Full config",
|
||||
spanName: "my-span",
|
||||
d: caddyfile.NewTestDispenser(`
|
||||
tracing {
|
||||
span my-span
|
||||
}`),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Only span name in the config",
|
||||
spanName: "my-span",
|
||||
d: caddyfile.NewTestDispenser(`
|
||||
tracing {
|
||||
span my-span
|
||||
}`),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Empty config",
|
||||
d: caddyfile.NewTestDispenser(`
|
||||
tracing {
|
||||
}`),
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ot := &Tracing{}
|
||||
if err := ot.UnmarshalCaddyfile(tt.d); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalCaddyfile() error = %v, wantErrType %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
if ot.SpanName != tt.spanName {
|
||||
t.Errorf("UnmarshalCaddyfile() SpanName = %v, want SpanName %v", ot.SpanName, tt.spanName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTracing_UnmarshalCaddyfile_Error(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
d *caddyfile.Dispenser
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Unknown parameter",
|
||||
d: caddyfile.NewTestDispenser(`
|
||||
tracing {
|
||||
foo bar
|
||||
}`),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Missed argument",
|
||||
d: caddyfile.NewTestDispenser(`
|
||||
tracing {
|
||||
span
|
||||
}`),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ot := &Tracing{}
|
||||
if err := ot.UnmarshalCaddyfile(tt.d); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalCaddyfile() error = %v, wantErrType %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTracing_ServeHTTP_Propagation_Without_Initial_Headers(t *testing.T) {
|
||||
ot := &Tracing{
|
||||
SpanName: "mySpan",
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("GET", "https://example.com/foo", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
var handler caddyhttp.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) error {
|
||||
traceparent := request.Header.Get("Traceparent")
|
||||
if traceparent == "" || strings.HasPrefix(traceparent, "00-00000000000000000000000000000000-0000000000000000") {
|
||||
t.Errorf("Invalid traceparent: %v", traceparent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
|
||||
defer cancel()
|
||||
|
||||
if err := ot.Provision(ctx); err != nil {
|
||||
t.Errorf("Provision error: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if err := ot.ServeHTTP(w, req, handler); err != nil {
|
||||
t.Errorf("ServeHTTP error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTracing_ServeHTTP_Propagation_With_Initial_Headers(t *testing.T) {
|
||||
ot := &Tracing{
|
||||
SpanName: "mySpan",
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("GET", "https://example.com/foo", nil)
|
||||
req.Header.Set("traceparent", "00-11111111111111111111111111111111-1111111111111111-01")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
var handler caddyhttp.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) error {
|
||||
traceparent := request.Header.Get("Traceparent")
|
||||
if !strings.HasPrefix(traceparent, "00-11111111111111111111111111111111") {
|
||||
t.Errorf("Invalid traceparent: %v", traceparent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
|
||||
defer cancel()
|
||||
|
||||
if err := ot.Provision(ctx); err != nil {
|
||||
t.Errorf("Provision error: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if err := ot.ServeHTTP(w, req, handler); err != nil {
|
||||
t.Errorf("ServeHTTP error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTracing_ServeHTTP_Next_Error(t *testing.T) {
|
||||
ot := &Tracing{
|
||||
SpanName: "mySpan",
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("GET", "https://example.com/foo", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
expectErr := errors.New("test error")
|
||||
|
||||
var handler caddyhttp.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) error {
|
||||
return expectErr
|
||||
}
|
||||
|
||||
ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
|
||||
defer cancel()
|
||||
|
||||
if err := ot.Provision(ctx); err != nil {
|
||||
t.Errorf("Provision error: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if err := ot.ServeHTTP(w, req, handler); err == nil || !errors.Is(err, expectErr) {
|
||||
t.Errorf("expected error, got: %v", err)
|
||||
}
|
||||
}
|
108
modules/caddyhttp/tracing/tracer.go
Normal file
108
modules/caddyhttp/tracing/tracer.go
Normal file
|
@ -0,0 +1,108 @@
|
|||
package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
|
||||
caddycmd "github.com/caddyserver/caddy/v2/cmd"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
webEngineName = "Caddy"
|
||||
defaultSpanName = "handler"
|
||||
nextCallCtxKey caddy.CtxKey = "nextCall"
|
||||
)
|
||||
|
||||
// nextCall store the next handler, and the error value return on calling it (if any)
|
||||
type nextCall struct {
|
||||
next caddyhttp.Handler
|
||||
err error
|
||||
}
|
||||
|
||||
// openTelemetryWrapper is responsible for the tracing injection, extraction and propagation.
|
||||
type openTelemetryWrapper struct {
|
||||
propagators propagation.TextMapPropagator
|
||||
|
||||
handler http.Handler
|
||||
|
||||
spanName string
|
||||
}
|
||||
|
||||
// newOpenTelemetryWrapper is responsible for the openTelemetryWrapper initialization using provided configuration.
|
||||
func newOpenTelemetryWrapper(
|
||||
ctx context.Context,
|
||||
spanName string,
|
||||
) (openTelemetryWrapper, error) {
|
||||
if spanName == "" {
|
||||
spanName = defaultSpanName
|
||||
}
|
||||
|
||||
ot := openTelemetryWrapper{
|
||||
spanName: spanName,
|
||||
}
|
||||
|
||||
res, err := ot.newResource(webEngineName, caddycmd.CaddyVersion())
|
||||
if err != nil {
|
||||
return ot, fmt.Errorf("creating resource error: %w", err)
|
||||
}
|
||||
|
||||
traceExporter, err := otlptracegrpc.New(ctx)
|
||||
if err != nil {
|
||||
return ot, fmt.Errorf("creating trace exporter error: %w", err)
|
||||
}
|
||||
|
||||
ot.propagators = propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
|
||||
|
||||
tracerProvider := globalTracerProvider.getTracerProvider(
|
||||
sdktrace.WithBatcher(traceExporter),
|
||||
sdktrace.WithResource(res),
|
||||
)
|
||||
|
||||
ot.handler = otelhttp.NewHandler(http.HandlerFunc(ot.serveHTTP), ot.spanName, otelhttp.WithTracerProvider(tracerProvider), otelhttp.WithPropagators(ot.propagators))
|
||||
return ot, nil
|
||||
}
|
||||
|
||||
// serveHTTP injects a tracing context and call the next handler.
|
||||
func (ot *openTelemetryWrapper) serveHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
ot.propagators.Inject(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||
next := r.Context().Value(nextCallCtxKey).(*nextCall)
|
||||
next.err = next.next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// ServeHTTP propagates call to the by wrapped by `otelhttp` next handler.
|
||||
func (ot *openTelemetryWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
|
||||
n := &nextCall{
|
||||
next: next,
|
||||
err: nil,
|
||||
}
|
||||
ot.handler.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), nextCallCtxKey, n)))
|
||||
|
||||
return n.err
|
||||
}
|
||||
|
||||
// cleanup flush all remaining data and shutdown a tracerProvider
|
||||
func (ot *openTelemetryWrapper) cleanup(logger *zap.Logger) error {
|
||||
return globalTracerProvider.cleanupTracerProvider(logger)
|
||||
}
|
||||
|
||||
// newResource creates a resource that describe current handler instance and merge it with a default attributes value.
|
||||
func (ot *openTelemetryWrapper) newResource(
|
||||
webEngineName,
|
||||
webEngineVersion string,
|
||||
) (*resource.Resource, error) {
|
||||
return resource.Merge(resource.Default(), resource.NewSchemaless(
|
||||
semconv.WebEngineNameKey.String(webEngineName),
|
||||
semconv.WebEngineVersionKey.String(webEngineVersion),
|
||||
))
|
||||
}
|
27
modules/caddyhttp/tracing/tracer_test.go
Normal file
27
modules/caddyhttp/tracing/tracer_test.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
)
|
||||
|
||||
func TestOpenTelemetryWrapper_newOpenTelemetryWrapper(t *testing.T) {
|
||||
ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
|
||||
defer cancel()
|
||||
|
||||
var otw openTelemetryWrapper
|
||||
var err error
|
||||
|
||||
if otw, err = newOpenTelemetryWrapper(ctx,
|
||||
"",
|
||||
); err != nil {
|
||||
t.Errorf("newOpenTelemetryWrapper() error = %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if otw.propagators == nil {
|
||||
t.Errorf("Propagators should not be empty")
|
||||
}
|
||||
}
|
63
modules/caddyhttp/tracing/tracerprovider.go
Normal file
63
modules/caddyhttp/tracing/tracerprovider.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// globalTracerProvider stores global tracer provider and is responsible for graceful shutdown when nobody is using it.
|
||||
var globalTracerProvider = &tracerProvider{}
|
||||
|
||||
type tracerProvider struct {
|
||||
mu sync.Mutex
|
||||
tracerProvider *sdktrace.TracerProvider
|
||||
tracerProvidersCounter int
|
||||
}
|
||||
|
||||
// getTracerProvider create or return an existing global TracerProvider
|
||||
func (t *tracerProvider) getTracerProvider(opts ...sdktrace.TracerProviderOption) *sdktrace.TracerProvider {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
t.tracerProvidersCounter++
|
||||
|
||||
if t.tracerProvider == nil {
|
||||
t.tracerProvider = sdktrace.NewTracerProvider(
|
||||
opts...,
|
||||
)
|
||||
}
|
||||
|
||||
return t.tracerProvider
|
||||
}
|
||||
|
||||
// cleanupTracerProvider gracefully shutdown a TracerProvider
|
||||
func (t *tracerProvider) cleanupTracerProvider(logger *zap.Logger) error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if t.tracerProvidersCounter > 0 {
|
||||
t.tracerProvidersCounter--
|
||||
}
|
||||
|
||||
if t.tracerProvidersCounter == 0 {
|
||||
if t.tracerProvider != nil {
|
||||
// tracerProvider.ForceFlush SHOULD be invoked according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#forceflush
|
||||
if err := t.tracerProvider.ForceFlush(context.Background()); err != nil {
|
||||
logger.Error("forcing flush", zap.Error(err))
|
||||
}
|
||||
|
||||
// tracerProvider.Shutdown MUST be invoked according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#shutdown
|
||||
if err := t.tracerProvider.Shutdown(context.Background()); err != nil {
|
||||
return fmt.Errorf("tracerProvider shutdown error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
t.tracerProvider = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
43
modules/caddyhttp/tracing/tracerprovider_test.go
Normal file
43
modules/caddyhttp/tracing/tracerprovider_test.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package tracing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Test_tracersProvider_getTracerProvider(t *testing.T) {
|
||||
tp := tracerProvider{}
|
||||
|
||||
tp.getTracerProvider()
|
||||
tp.getTracerProvider()
|
||||
|
||||
if tp.tracerProvider == nil {
|
||||
t.Errorf("There should be tracer provider")
|
||||
}
|
||||
|
||||
if tp.tracerProvidersCounter != 2 {
|
||||
t.Errorf("Tracer providers counter should equal to 2")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_tracersProvider_cleanupTracerProvider(t *testing.T) {
|
||||
tp := tracerProvider{}
|
||||
|
||||
tp.getTracerProvider()
|
||||
tp.getTracerProvider()
|
||||
|
||||
err := tp.cleanupTracerProvider(zap.NewNop())
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error: %v", err)
|
||||
}
|
||||
|
||||
if tp.tracerProvider == nil {
|
||||
t.Errorf("There should be tracer provider")
|
||||
}
|
||||
|
||||
if tp.tracerProvidersCounter != 1 {
|
||||
t.Errorf("Tracer providers counter should equal to 1")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue