-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Andrii Kushch
committed
Sep 27, 2021
1 parent
501da21
commit 7a2bd8a
Showing
12 changed files
with
952 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
:80 { | ||
opentelemetry /myhandler { | ||
span_name my-span | ||
} | ||
} | ||
---------- | ||
{ | ||
"apps": { | ||
"http": { | ||
"servers": { | ||
"srv0": { | ||
"listen": [ | ||
":80" | ||
], | ||
"routes": [ | ||
{ | ||
"match": [ | ||
{ | ||
"path": [ | ||
"/myhandler" | ||
] | ||
} | ||
], | ||
"handle": [ | ||
{ | ||
"span_name": "my-span", | ||
} | ||
] | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# OpenTelemetry module | ||
|
||
This module provides integration with OpenTelemetry tracing facilities. It is implemented | ||
as `caddyhttp.MiddlewareHandler` and can be chained into a list of other handlers. | ||
|
||
When enabled, it propagates an existing tracing context or will init a new one otherwise. | ||
|
||
It is based on `https://github.com/open-telemetry/opentelemetry-go`. | ||
|
||
## Configuration | ||
|
||
### Environment variables | ||
|
||
It can be configured using environment variables defined | ||
by [spec](https://github.com/open-telemetry/opentelemetry-specification). | ||
|
||
IMPORTANT: Please, consider the version | ||
of [https://github.com/open-telemetry/opentelemetry-go](https://github.com/open-telemetry/opentelemetry-go). Some parts | ||
of the specification may be not implemented yet. | ||
|
||
Required by module environment variables are: OTEL_EXPORTER_OTLP_PROTOCOL/OTEL_EXPORTER_OTLP_TRACES_PROTOCOL and | ||
OTEL_PROPAGATORS. | ||
|
||
If neither OTEL_EXPORTER_OTLP_INSECURE nor OTEL_EXPORTER_OTLP_SPAN_INSECURE is provided, then: | ||
|
||
1. If OTEL_EXPORTER_OTLP_CERTIFICATE or OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE are specified they will be used for TLS. | ||
2. Else if both OTEL_EXPORTER_OTLP_CERTIFICATE and OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE are not specified, then default | ||
TLS with the default `tls.Config` config will be used for an exporter. | ||
|
||
For the exporter configuration details, please | ||
see [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/a4440931b522c7351b0485ff4899f786b4ff4459/specification/protocol/exporter.md) | ||
. | ||
|
||
Example: | ||
|
||
```bash | ||
export OTEL_EXPORTER_OTLP_HEADERS="myAuthHeader=myToken" | ||
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc | ||
export OTEL_PROPAGATORS=tracecontext,baggage | ||
export OTEL_EXPORTER_OTLP_SPAN_INSECURE=false | ||
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=localhost:12345 | ||
``` | ||
|
||
### Caddy file configuration | ||
|
||
Here is an example of **Caddyfile**: | ||
|
||
``` | ||
handle /myHanlder { | ||
opentelemetry { | ||
span_name my-span | ||
} | ||
reverse_proxy 127.0.0.1:8081 | ||
} | ||
``` | ||
|
||
Please check span | ||
naming [guideline](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#span) | ||
. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package opentelemetry | ||
|
||
import ( | ||
"errors" | ||
"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(OpenTelemetry{}) | ||
httpcaddyfile.RegisterHandlerDirective("opentelemetry", parseCaddyfile) | ||
} | ||
|
||
// OpenTelemetry implements an HTTP handler that adds support for the opentelemetry tracing. | ||
// It is responsible for the injection and propagation of the tracing contexts. | ||
// OpenTelemetry module can be configured via environment variables https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md. Some values can be overwritten with values from the configuration file. | ||
type OpenTelemetry struct { | ||
// SpanName is a span name. It SHOULD follow the naming guideline https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#span | ||
SpanName string `json:"span_name"` | ||
|
||
// otel implements opentelemetry related logic. | ||
otel openTelemetryWrapper | ||
|
||
logger *zap.Logger | ||
} | ||
|
||
// CaddyModule returns the Caddy module information. | ||
func (OpenTelemetry) CaddyModule() caddy.ModuleInfo { | ||
return caddy.ModuleInfo{ | ||
ID: "http.handlers.opentelemetry", | ||
New: func() caddy.Module { return new(OpenTelemetry) }, | ||
} | ||
} | ||
|
||
// Provision implements caddy.Provisioner. | ||
func (ot *OpenTelemetry) 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 *OpenTelemetry) Cleanup() error { | ||
if err := ot.otel.cleanup(ot.logger); err != nil { | ||
return fmt.Errorf("tracerProvider shutdown: %w", err) | ||
} | ||
return nil | ||
} | ||
|
||
// Validate implements caddy.Validator. | ||
func (ot *OpenTelemetry) Validate() error { | ||
if ot.otel.tracer == nil { | ||
return errors.New("openTelemetry tracer is nil") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// ServeHTTP implements caddyhttp.MiddlewareHandler. | ||
func (ot *OpenTelemetry) 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. | ||
func (ot *OpenTelemetry) 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_name": &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 OpenTelemetry | ||
err := m.UnmarshalCaddyfile(h.Dispenser) | ||
return &m, err | ||
} | ||
|
||
// Interface guards | ||
var ( | ||
_ caddy.Provisioner = (*OpenTelemetry)(nil) | ||
_ caddy.Validator = (*OpenTelemetry)(nil) | ||
_ caddyhttp.MiddlewareHandler = (*OpenTelemetry)(nil) | ||
_ caddyfile.Unmarshaler = (*OpenTelemetry)(nil) | ||
) |
Oops, something went wrong.