UNPKG

@fiberplane/hono-otel

Version:

Hono middleware to forward OpenTelemetry traces to a local instance of @fiberplane/studio

95 lines (94 loc) 3.44 kB
import { getLogLevel, getMode, getOtelEndpoint, getOtelToken, getServiceName, } from "./resolvers.js"; /** * OpenTelemetry advises that instrumentations should require explicit configuration of which headers to capture. * * We want to minimize configuration, so instead, we've chosen to ignore the following headers by default. * * In practice, the library only redacts their values when running in "production" mode. */ export const DEFAULT_REDACTED_HEADERS = [ "authorization", "cookie", "set-cookie", "x-api-key", "x-amz-security-token", "x-real-ip", "x-forwarded-for", "proxy-authorization", "www-authenticate", "proxy-authenticate", "x-real-ip", "x-auth-token", "x-csrf-token", "x-session-id", "neon-connection-string", ]; export const DEFAULT_REDACTED_QUERY_PARAMS = [ "code", "token", "access_token", "refresh_token", "id_token", "state", "secret", "password", "api_key", ]; export const DEFAULT_CONFIG = Object.freeze({ redactedHeaders: [...DEFAULT_REDACTED_HEADERS], redactedQueryParams: [...DEFAULT_REDACTED_QUERY_PARAMS], libraryDebugMode: false, monitor: { fetch: true, logging: true, cfBindings: true, }, }); export function resolveConfig(userConfig, env) { const config = mergeConfigs(DEFAULT_CONFIG, userConfig); const otelEndpoint = getOtelEndpoint(env); // NOTE - Instrumentation is enabled if the FIBERPLANE_OTEL_ENDPOINT is set. // This means we do *not* want to have a default for the FIBERPLANE_OTEL_ENDPOINT (prev: FPX_ENDPOINT), // Otherwise, users might accidentally deploy to production with our middleware and // start sending data to the default url. const enabled = !!otelEndpoint && typeof otelEndpoint === "string"; // NOTE - "local" mode will send the kitchen sink with every trace: env vars, request bodies, etc. const mode = getMode(otelEndpoint, userConfig, env); const otelToken = getOtelToken(env); const logLevel = getLogLevel(config, env); const serviceName = getServiceName(env, "unknown"); const redactedHeaders = new Set(config.redactedHeaders); const redactedQueryParams = new Set(config.redactedQueryParams); return { ...config, redactedHeaders, redactedQueryParams, enabled, mode, otelEndpoint, otelToken, logLevel, serviceName, }; } /** * Last-in-wins deep merge for {@link FpConfig} */ function mergeConfigs(fallbackConfig, userConfig) { const libraryDebugMode = typeof userConfig?.libraryDebugMode === "boolean" ? userConfig.libraryDebugMode : fallbackConfig.libraryDebugMode; return { libraryDebugMode, redactedHeaders: mergeRedactedHeaders(fallbackConfig.redactedHeaders, userConfig?.redactedHeaders), redactedQueryParams: mergeRedactedQueryParams(fallbackConfig.redactedQueryParams, userConfig?.redactedQueryParams), monitor: Object.assign({}, fallbackConfig.monitor, userConfig?.monitor), }; } function mergeRedactedHeaders(fallbackHeaders, userHeaders) { const lowerCaseUserHeaders = (userHeaders ?? []).map((header) => header.toLowerCase()); return [...fallbackHeaders, ...lowerCaseUserHeaders]; } function mergeRedactedQueryParams(fallbackParams, userParams) { return [...fallbackParams, ...(userParams ?? [])]; }