diff --git a/cli/deployment/config.go b/cli/deployment/config.go index 12f62ab7be08d..f3e432fb559d3 100644 --- a/cli/deployment/config.go +++ b/cli/deployment/config.go @@ -289,10 +289,18 @@ func newConfig() *codersdk.DeploymentConfig { Default: "tls12", }, }, - TraceEnable: &codersdk.DeploymentConfigField[bool]{ - Name: "Trace Enable", - Usage: "Whether application tracing data is collected.", - Flag: "trace", + Trace: &codersdk.TraceConfig{ + Enable: &codersdk.DeploymentConfigField[bool]{ + Name: "Trace Enable", + Usage: "Whether application tracing data is collected. It exports to a backend configured by environment variables. See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md", + Flag: "trace", + }, + HoneycombAPIKey: &codersdk.DeploymentConfigField[string]{ + Name: "Trace Honeycomb API Key", + Usage: "Enables trace exporting to Honeycomb.io using the provided API Key.", + Flag: "trace-honeycomb-api-key", + Secret: true, + }, }, SecureAuthCookie: &codersdk.DeploymentConfigField[bool]{ Name: "Secure Auth Cookie", diff --git a/cli/deployment/config_test.go b/cli/deployment/config_test.go index 4fd2cc5978673..d86c8e06a29b6 100644 --- a/cli/deployment/config_test.go +++ b/cli/deployment/config_test.go @@ -114,6 +114,16 @@ func TestConfig(t *testing.T) { require.Equal(t, config.TLS.Enable.Value, true) require.Equal(t, config.TLS.MinVersion.Value, "tls10") }, + }, { + Name: "Trace", + Env: map[string]string{ + "CODER_TRACE_ENABLE": "true", + "CODER_TRACE_HONEYCOMB_API_KEY": "my-honeycomb-key", + }, + Valid: func(config *codersdk.DeploymentConfig) { + require.Equal(t, config.Trace.Enable.Value, true) + require.Equal(t, config.Trace.HoneycombAPIKey.Value, "my-honeycomb-key") + }, }, { Name: "OIDC", Env: map[string]string{ @@ -192,6 +202,7 @@ func TestConfig(t *testing.T) { }} { tc := tc t.Run(tc.Name, func(t *testing.T) { + t.Helper() for key, value := range tc.Env { t.Setenv(key, value) } diff --git a/cli/server.go b/cli/server.go index 93de4e5e34960..60455f158d9be 100644 --- a/cli/server.go +++ b/cli/server.go @@ -125,9 +125,9 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co shouldCoderTrace = cfg.Telemetry.Trace.Value } - if cfg.TraceEnable.Value || shouldCoderTrace { + if cfg.Trace.Enable.Value || shouldCoderTrace { sdkTracerProvider, closeTracing, err := tracing.TracerProvider(ctx, "coderd", tracing.TracerOpts{ - Default: cfg.TraceEnable.Value, + Default: cfg.Trace.Enable.Value, Coder: shouldCoderTrace, }) if err != nil { diff --git a/coderd/tracing/exporter.go b/coderd/tracing/exporter.go index ce232c39a38ae..de4579889f527 100644 --- a/coderd/tracing/exporter.go +++ b/coderd/tracing/exporter.go @@ -13,6 +13,7 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.11.0" "golang.org/x/xerrors" + "google.golang.org/grpc/credentials" ) // TracerOpts specifies which telemetry exporters should be configured. @@ -23,6 +24,8 @@ type TracerOpts struct { // Coder exports traces to Coder's public tracing ingest service and is used // to improve the product. It is disabled when opting out of telemetry. Coder bool + // Exports traces to Honeycomb.io with the provided API key. + Honeycomb string } // TracerProvider creates a grpc otlp exporter and configures a trace provider. @@ -57,6 +60,14 @@ func TracerProvider(ctx context.Context, service string, opts TracerOpts) (*sdkt closers = append(closers, exporter.Shutdown) tracerOpts = append(tracerOpts, sdktrace.WithBatcher(exporter)) } + if opts.Honeycomb != "" { + exporter, err := HoneycombExporter(ctx, opts.Honeycomb) + if err != nil { + return nil, nil, xerrors.Errorf("honeycomb exporter: %w", err) + } + closers = append(closers, exporter.Shutdown) + tracerOpts = append(tracerOpts, sdktrace.WithBatcher(exporter)) + } tracerProvider := sdktrace.NewTracerProvider(tracerOpts...) otel.SetTracerProvider(tracerProvider) @@ -101,3 +112,20 @@ func CoderExporter(ctx context.Context) (*otlptrace.Exporter, error) { return exporter, nil } + +func HoneycombExporter(ctx context.Context, apiKey string) (*otlptrace.Exporter, error) { + opts := []otlptracegrpc.Option{ + otlptracegrpc.WithEndpoint("api.honeycomb.io:443"), + otlptracegrpc.WithHeaders(map[string]string{ + "x-honeycomb-team": apiKey, + }), + otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")), + } + + exporter, err := otlptrace.New(ctx, otlptracegrpc.NewClient(opts...)) + if err != nil { + return nil, xerrors.Errorf("create otlp exporter: %w", err) + } + + return exporter, nil +} diff --git a/codersdk/deploymentconfig.go b/codersdk/deploymentconfig.go index 35df5733d62ec..a73385670575a 100644 --- a/codersdk/deploymentconfig.go +++ b/codersdk/deploymentconfig.go @@ -29,7 +29,7 @@ type DeploymentConfig struct { OIDC *OIDCConfig `json:"oidc" typescript:",notnull"` Telemetry *TelemetryConfig `json:"telemetry" typescript:",notnull"` TLS *TLSConfig `json:"tls" typescript:",notnull"` - TraceEnable *DeploymentConfigField[bool] `json:"trace_enable" typescript:",notnull"` + Trace *TraceConfig `json:"trace" typescript:",notnull"` SecureAuthCookie *DeploymentConfigField[bool] `json:"secure_auth_cookie" typescript:",notnull"` SSHKeygenAlgorithm *DeploymentConfigField[string] `json:"ssh_keygen_algorithm" typescript:",notnull"` AutoImportTemplates *DeploymentConfigField[[]string] `json:"auto_import_templates" typescript:",notnull"` @@ -107,6 +107,11 @@ type TLSConfig struct { MinVersion *DeploymentConfigField[string] `json:"min_version" typescript:",notnull"` } +type TraceConfig struct { + Enable *DeploymentConfigField[bool] `json:"enable" typescript:",notnull"` + HoneycombAPIKey *DeploymentConfigField[string] `json:"honeycomb_api_key" typescript:",notnull"` +} + type GitAuthConfig struct { ID string `json:"id"` Type string `json:"type"` diff --git a/go.mod b/go.mod index 0dee1d439f3b4..afa94bed5368b 100644 --- a/go.mod +++ b/go.mod @@ -303,7 +303,7 @@ require ( golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de // indirect - google.golang.org/grpc v1.50.1 // indirect + google.golang.org/grpc v1.50.1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/yaml.v2 v2.4.0 // indirect howett.net/plist v1.0.0 // indirect diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 3d1e0dd33badf..2c704b1988e85 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -292,7 +292,7 @@ export interface DeploymentConfig { readonly oidc: OIDCConfig readonly telemetry: TelemetryConfig readonly tls: TLSConfig - readonly trace_enable: DeploymentConfigField + readonly trace: TraceConfig readonly secure_auth_cookie: DeploymentConfigField readonly ssh_keygen_algorithm: DeploymentConfigField readonly auto_import_templates: DeploymentConfigField @@ -664,6 +664,12 @@ export interface TemplateVersionsByTemplateRequest extends Pagination { readonly template_id: string } +// From codersdk/deploymentconfig.go +export interface TraceConfig { + readonly enable: DeploymentConfigField + readonly honeycomb_api_key: DeploymentConfigField +} + // From codersdk/templates.go export interface UpdateActiveTemplateVersion { readonly id: string