Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add opentelementry implementation #295

Merged
merged 48 commits into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
b28f510
Add basic otel trace(r)
Aug 16, 2021
a4cf478
Use log entry with context
Aug 20, 2021
f51b4a6
Fix nil fields while logging metrics endpoint
Aug 30, 2021
42febb5
Moved metrics init to telemetry pkg
Aug 30, 2021
64b7389
add basic metrics and tracing
Aug 30, 2021
e871ba4
Trace statusCode
Aug 31, 2021
04ebed1
Add otel tracing for client req and endpoint related kinds
Sep 2, 2021
299aa93
add couper uid to trace spans
Sep 3, 2021
8f3d58a
Refactor uid as middleware
Sep 6, 2021
86bcba9
Fix endpoint log handler kind for Stringer interface
Sep 7, 2021
123c2da
expose receiver port
Sep 7, 2021
aa8a139
Fix span start with configured traceProvider
Sep 7, 2021
9e36a8f
Refine trace spans, replaced backend span with events
Sep 7, 2021
d215b33
Refactor responseWriter and accessLog to be setup and called within m…
Sep 8, 2021
97acc97
Add client/backend request counter
Sep 8, 2021
23a3b42
Add go instrumentation if exporter kind is prometheus
Sep 8, 2021
c744940
Add backend and connection metrics / traces
Sep 8, 2021
4d16577
Add more metrics and grafana dashboard
Sep 9, 2021
00e9f0e
Add settings metrics exporter switch and additional opts
Sep 10, 2021
da57678
auto provision current couper dashboard
Sep 10, 2021
d1ed7eb
uid from context may be nil
Sep 10, 2021
6e8ed9c
Fix setting gzipReader on nil beresps
Sep 15, 2021
b35e425
Fix wrong header removal
Sep 15, 2021
008635d
Fix missing early out on roundtrip error
Sep 15, 2021
3341446
Fixup run cmd test: add missing telemetry defaults
Sep 15, 2021
369054a
Add error type metric
Sep 15, 2021
2162d45
Refine grafana http status code panel
Sep 15, 2021
409e584
Add prom metrics test
Sep 15, 2021
ac2e23c
scrape logs as debug log level
Sep 16, 2021
c4cff34
Prefix metrics names with couper_
Sep 16, 2021
9770246
fixup grafana variables
Sep 16, 2021
7686455
improved grafana dashboard, error metrics and added method label
Sep 16, 2021
448dd0a
Dashboard refinements
Sep 17, 2021
c467d93
Add metrics for client connections
Sep 17, 2021
d290d8d
fix exporter init
Sep 17, 2021
7c8decb
default metrics exporter is prometheus
Sep 17, 2021
a49d23e
metrics and traces are a beta feature
Sep 17, 2021
707cb13
Fixup metrics testcase
Sep 17, 2021
538a363
change otel api to rc3
Sep 17, 2021
32fb7a1
sync test server start and cancel
Sep 20, 2021
f8cdc8f
fix race condition with own meter mutexed var
Sep 20, 2021
631d5e2
fixup
Sep 20, 2021
baed099
Change to beta options
Sep 21, 2021
0e6afbb
remove unstable metric
Sep 21, 2021
2108cc4
Fixup global meter provider for oltp metrics exporter
Sep 21, 2021
3060fee
record client request start time asap
Sep 22, 2021
f2e73bb
use nil check instead of obsolete type assertion
Sep 22, 2021
34890b9
Fix trace insecure setting
Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion command/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"strings"
"sync"
"time"

"github.com/sirupsen/logrus"

Expand All @@ -18,6 +19,7 @@ import (
"github.com/avenga/couper/errors"
"github.com/avenga/couper/server"
"github.com/avenga/couper/server/writer"
"github.com/avenga/couper/telemetry"
)

var _ Cmd = &Run{}
Expand All @@ -43,11 +45,17 @@ func NewRun(ctx context.Context) *Run {
set.Var(&AcceptForwardedValue{settings: &settings}, "accept-forwarded-url", "-accept-forwarded-url [proto][,host][,port]")
set.Var(&settings.TLSDevProxy, "https-dev-proxy", "-https-dev-proxy 8443:8080,9443:9000")
set.BoolVar(&settings.NoProxyFromEnv, "no-proxy-from-env", settings.NoProxyFromEnv, "-no-proxy-from-env")
set.StringVar(&settings.RequestIDFormat, "request-id-format", settings.RequestIDFormat, "-request-id-format uuid4")
set.StringVar(&settings.RequestIDAcceptFromHeader, "request-id-accept-from-header", settings.RequestIDAcceptFromHeader, "-request-id-accept-from-header X-UID")
set.StringVar(&settings.RequestIDBackendHeader, "request-id-backend-header", settings.RequestIDBackendHeader, "-request-id-backend-header Couper-Request-ID")
set.StringVar(&settings.RequestIDClientHeader, "request-id-client-header", settings.RequestIDClientHeader, "-request-id-client-header Couper-Request-ID")
set.StringVar(&settings.RequestIDFormat, "request-id-format", settings.RequestIDFormat, "-request-id-format uuid4")
set.StringVar(&settings.SecureCookies, "secure-cookies", settings.SecureCookies, "-secure-cookies strip")
set.BoolVar(&settings.TelemetryMetrics, "beta-metrics", settings.TelemetryMetrics, "-metrics")
set.IntVar(&settings.TelemetryMetricsPort, "beta-metrics-port", settings.TelemetryMetricsPort, "-metrics-port 9090")
set.StringVar(&settings.TelemetryMetricsEndpoint, "beta-metrics-endpoint", settings.TelemetryMetricsEndpoint, "-metrics-endpoint [host:port]")
set.StringVar(&settings.TelemetryMetricsExporter, "beta-metrics-exporter", settings.TelemetryMetricsExporter, "-metrics-exporter [name]")
set.BoolVar(&settings.TelemetryTraces, "beta-traces", settings.TelemetryTraces, "-traces")
set.StringVar(&settings.TelemetryTracesEndpoint, "beta-traces-endpoint", settings.TelemetryTracesEndpoint, "-traces-endpoint [host:port]")
return &Run{
context: ctx,
flagSet: set,
Expand Down Expand Up @@ -109,6 +117,16 @@ func (r *Run) Execute(args Args, config *config.Couper, logEntry *logrus.Entry)
timings := runtime.DefaultTimings
env.Decode(&timings)

telemetry.InitExporter(r.context, &telemetry.Options{
MetricsCollectPeriod: time.Second * 2,
Metrics: r.settings.TelemetryMetrics,
MetricsEndpoint: r.settings.TelemetryMetricsEndpoint,
MetricsExporter: r.settings.TelemetryMetricsExporter,
MetricsPort: r.settings.TelemetryMetricsPort,
Traces: r.settings.TelemetryTraces,
TracesEndpoint: r.settings.TelemetryTracesEndpoint,
}, logEntry)

// logEntry has still the 'daemon' type which can be used for config related load errors.
srvConf, err := runtime.NewServerConfiguration(config, logEntry, cache.New(logEntry, r.context.Done()))
if err != nil {
Expand Down Expand Up @@ -158,6 +176,7 @@ func (r *Run) Execute(args Args, config *config.Couper, logEntry *logrus.Entry)
_ = s.Close()
logEntry.Infof("Server closed: %s", s.Addr)
}

return nil
}

Expand Down
72 changes: 42 additions & 30 deletions command/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,51 @@ func TestNewRun(t *testing.T) {
}{
{"defaults from file", "01_defaults.hcl", nil, nil, &defaultSettings},
{"overrides from file", "02_changed_defaults.hcl", nil, nil, &config.Settings{
DefaultPort: 9090,
HealthPath: "/status/health",
NoProxyFromEnv: true,
LogFormat: defaultSettings.LogFormat,
LogLevel: defaultSettings.LogLevel,
RequestIDFormat: "uuid4",
RequestIDBackendHeader: defaultSettings.RequestIDBackendHeader,
RequestIDClientHeader: defaultSettings.RequestIDClientHeader,
XForwardedHost: true,
AcceptForwardedURL: []string{},
AcceptForwarded: &config.AcceptForwarded{},
AcceptForwarded: &config.AcceptForwarded{},
AcceptForwardedURL: []string{},
DefaultPort: 9090,
HealthPath: "/status/health",
LogFormat: defaultSettings.LogFormat,
LogLevel: defaultSettings.LogLevel,
NoProxyFromEnv: true,
RequestIDBackendHeader: defaultSettings.RequestIDBackendHeader,
RequestIDClientHeader: defaultSettings.RequestIDClientHeader,
RequestIDFormat: "uuid4",
TelemetryMetricsEndpoint: defaultSettings.TelemetryMetricsEndpoint,
TelemetryMetricsExporter: defaultSettings.TelemetryMetricsExporter,
TelemetryMetricsPort: defaultSettings.TelemetryMetricsPort,
TelemetryTracesEndpoint: defaultSettings.TelemetryTracesEndpoint,
XForwardedHost: true,
}},
{"defaults with flag port", "01_defaults.hcl", Args{"-p", "9876"}, nil, &config.Settings{
DefaultPort: 9876,
HealthPath: defaultSettings.HealthPath,
LogFormat: defaultSettings.LogFormat,
LogLevel: defaultSettings.LogLevel,
RequestIDFormat: defaultSettings.LogFormat,
RequestIDBackendHeader: defaultSettings.RequestIDBackendHeader,
RequestIDClientHeader: defaultSettings.RequestIDClientHeader,
AcceptForwardedURL: []string{},
AcceptForwarded: &config.AcceptForwarded{},
AcceptForwarded: &config.AcceptForwarded{},
AcceptForwardedURL: []string{},
DefaultPort: 9876,
HealthPath: defaultSettings.HealthPath,
LogFormat: defaultSettings.LogFormat,
LogLevel: defaultSettings.LogLevel,
RequestIDBackendHeader: defaultSettings.RequestIDBackendHeader,
RequestIDClientHeader: defaultSettings.RequestIDClientHeader,
RequestIDFormat: defaultSettings.LogFormat,
TelemetryMetricsEndpoint: defaultSettings.TelemetryMetricsEndpoint,
TelemetryMetricsExporter: defaultSettings.TelemetryMetricsExporter,
TelemetryMetricsPort: defaultSettings.TelemetryMetricsPort,
TelemetryTracesEndpoint: defaultSettings.TelemetryTracesEndpoint,
}},
{"defaults with flag and env port", "01_defaults.hcl", Args{"-p", "9876"}, []string{"COUPER_DEFAULT_PORT=4561"}, &config.Settings{
DefaultPort: 4561,
HealthPath: defaultSettings.HealthPath,
LogFormat: defaultSettings.LogFormat,
LogLevel: defaultSettings.LogLevel,
RequestIDFormat: defaultSettings.LogFormat,
RequestIDBackendHeader: defaultSettings.RequestIDBackendHeader,
RequestIDClientHeader: defaultSettings.RequestIDClientHeader,
AcceptForwardedURL: []string{},
AcceptForwarded: &config.AcceptForwarded{},
AcceptForwarded: &config.AcceptForwarded{},
AcceptForwardedURL: []string{},
DefaultPort: 4561,
HealthPath: defaultSettings.HealthPath,
LogFormat: defaultSettings.LogFormat,
LogLevel: defaultSettings.LogLevel,
RequestIDBackendHeader: defaultSettings.RequestIDBackendHeader,
RequestIDClientHeader: defaultSettings.RequestIDClientHeader,
RequestIDFormat: defaultSettings.LogFormat,
TelemetryMetricsEndpoint: defaultSettings.TelemetryMetricsEndpoint,
TelemetryMetricsExporter: defaultSettings.TelemetryMetricsExporter,
TelemetryMetricsPort: defaultSettings.TelemetryMetricsPort,
TelemetryTracesEndpoint: defaultSettings.TelemetryTracesEndpoint,
}},
}
for _, tt := range tests {
Expand Down Expand Up @@ -101,7 +113,7 @@ func TestNewRun(t *testing.T) {
time.Sleep(time.Second / 4)
runCmd.settingsMu.Lock()
if !reflect.DeepEqual(couperFile.Settings, tt.settings) {
t.Errorf("Settings differ:\nwant:\t%#v\ngot:\t%#v\n", tt.settings, couperFile.Settings)
t.Errorf("Settings differ: %s:\nwant:\t%#v\ngot:\t%#v\n", tt.name, tt.settings, couperFile.Settings)
}
runCmd.settingsMu.Unlock()

Expand Down
3 changes: 3 additions & 0 deletions config/request/context_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ const (
Endpoint
EndpointKind
Error
Handler
LogDebugLevel
LogEntry
OpenAPI
PathParams
ResponseWriter
RoundTripName
RoundTripProxy
ServerName
StartTime
TokenRequest
TokenRequestRetries
UID
Expand Down
41 changes: 26 additions & 15 deletions config/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,24 @@ func (a AcceptForwarded) String() string {
return strings.Join(parts, ",")
}

const otelCollectorEndpoint = "localhost:4317"

// DefaultSettings defines the <DefaultSettings> object.
var DefaultSettings = Settings{
DefaultPort: 8080,
HealthPath: "/healthz",
LogFormat: "common",
LogLevel: "info",
LogPretty: false,
NoProxyFromEnv: false,
RequestIDFormat: "common",
RequestIDAcceptFromHeader: "",
RequestIDBackendHeader: "Couper-Request-ID",
RequestIDClientHeader: "Couper-Request-ID",
SecureCookies: "",
XForwardedHost: false,
DefaultPort: 8080,
HealthPath: "/healthz",
LogFormat: "common",
LogLevel: "info",
LogPretty: false,
NoProxyFromEnv: false,
RequestIDBackendHeader: "Couper-Request-ID",
RequestIDClientHeader: "Couper-Request-ID",
RequestIDFormat: "common",
TelemetryMetricsEndpoint: otelCollectorEndpoint,
TelemetryMetricsExporter: "prometheus",
TelemetryMetricsPort: 9090, // default prometheus port
TelemetryTracesEndpoint: otelCollectorEndpoint,
XForwardedHost: false,

// TODO: refactor
AcceptForwardedURL: []string{},
Expand All @@ -70,21 +74,28 @@ var DefaultSettings = Settings{

// Settings represents the <Settings> object.
type Settings struct {
AcceptForwarded *AcceptForwarded

AcceptForwardedURL []string `hcl:"accept_forwarded_url,optional"`
DefaultPort int `hcl:"default_port,optional"`
HealthPath string `hcl:"health_path,optional"`
LogFormat string `hcl:"log_format,optional"`
LogLevel string `hcl:"log_level,optional"`
LogPretty bool `hcl:"log_pretty,optional"`
NoProxyFromEnv bool `hcl:"no_proxy_from_env,optional"`
RequestIDFormat string `hcl:"request_id_format,optional"`
RequestIDAcceptFromHeader string `hcl:"request_id_accept_from_header,optional"`
RequestIDBackendHeader string `hcl:"request_id_backend_header,optional"`
RequestIDClientHeader string `hcl:"request_id_client_header,optional"`
RequestIDFormat string `hcl:"request_id_format,optional"`
SecureCookies string `hcl:"secure_cookies,optional"`
TLSDevProxy List `hcl:"https_dev_proxy,optional"`
TelemetryMetrics bool `hcl:"beta_metrics,optional"`
TelemetryMetricsPort int `hcl:"beta_metrics_port,optional"`
TelemetryMetricsEndpoint string `hcl:"beta_metrics_endpoint,optional"`
TelemetryMetricsExporter string `hcl:"beta_metrics_exporter,optional"`
TelemetryTraces bool `hcl:"beta_traces,optional"`
TelemetryTracesEndpoint string `hcl:"beta_traces_endpoint,optional"`
XForwardedHost bool `hcl:"xfh,optional"`
AcceptForwardedURL []string `hcl:"accept_forwarded_url,optional"`
AcceptForwarded *AcceptForwarded
}

var _ flag.Value = &List{}
Expand Down
10 changes: 5 additions & 5 deletions errors/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,16 @@ func (e *Error) Unwrap() error {

// LogError contains additional context which should be used for logging purposes only.
func (e *Error) LogError() string {
msg := appendMsg(e.synopsis, e.label, e.message)
msg := AppendMsg(e.synopsis, e.label, e.message)

if e.inner != nil {
if innr, ok := e.inner.(*Error); ok {
if Equals(e, innr) {
innr.synopsis = "" // at least for one level, prevent duplicated synopsis
}
return appendMsg(msg, innr.LogError())
return AppendMsg(msg, innr.LogError())
}
msg = appendMsg(msg, e.inner.Error())
msg = AppendMsg(msg, e.inner.Error())
}

return msg
Expand All @@ -127,8 +127,8 @@ func (e *Error) HTTPStatus() int {
return e.httpStatus
}

// appendMsg chains the given strings with ": " as separator.
func appendMsg(target string, messages ...string) string {
// AppendMsg chains the given strings with ": " as separator.
func AppendMsg(target string, messages ...string) string {
result := target
for _, m := range messages {
if result != "" && m != "" {
Expand Down
38 changes: 0 additions & 38 deletions errors/log.go

This file was deleted.

8 changes: 4 additions & 4 deletions eval/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func getFormParams(ctx *hcl.EvalContext, req *http.Request, attrs map[string]*hc
return nil
}

log := req.Context().Value(request.LogEntry).(*logrus.Entry)
log := req.Context().Value(request.LogEntry).(*logrus.Entry).WithContext(req.Context())

if req.Method != http.MethodPost {
log.WithError(errors.Evaluation.Label("form_params").
Expand Down Expand Up @@ -329,8 +329,8 @@ func ApplyResponseContext(ctx context.Context, body hcl.Body, beresp *http.Respo
return nil
}

content, _, _ := body.PartialContent(config.BackendInlineSchema)
if attr, ok := content.Attributes["set_response_status"]; ok {
bodyContent, _, _ := body.PartialContent(config.BackendInlineSchema)
if attr, ok := bodyContent.Attributes["set_response_status"]; ok {
_, err := ApplyResponseStatus(ctx, attr, beresp)
return err
}
Expand Down Expand Up @@ -358,7 +358,7 @@ func ApplyResponseStatus(ctx context.Context, attr *hcl.Attribute, beresp *http.
if beresp != nil {
if status == 204 {
beresp.Request.Context().
Value(request.LogEntry).(*logrus.Entry).
Value(request.LogEntry).(*logrus.Entry).WithContext(ctx).
Warn("set_response_status: removing body, if any due to status-code 204")

beresp.Body = io.NopCloser(bytes.NewBuffer([]byte{}))
Expand Down
Loading