using Microsoft.Extensions.Logging; namespace GB5Shared.Telemetry; /// /// OpenTelemetry configuration bound from the "OpenTelemetry" section of appsettings.json. /// All properties carry production-safe defaults so services with no config section work /// exactly as before (Zipkin at localhost:9411, always-sample, metrics enabled). /// public sealed class TelemetryOptions { /// appsettings.json section key. public const string SectionName = "OpenTelemetry"; /// /// The real, running service's name (e.g. "GB5-PAYROLL", "GB5-FRAMEWORK"). /// Set automatically by AddGB5Telemetry from the serviceName argument passed /// in each service's Program.cs — never hardcode this elsewhere. Consumed by /// RequestTracingMiddleware for the TOBSERVABILITY sink so every service reports /// its own identity instead of a shared literal. /// public string ServiceName { get; set; } = "GB5"; /// /// Master on/off switch. Set to false to disable all OTel instrumentation /// (tracing, metrics, enrichment) without removing the registration code. /// public bool Enabled { get; set; } = true; /// /// Trace and metric exporter backend. Supported values (case-insensitive): /// /// ZIPKIN — export to Zipkin HTTP endpoint (default, matches existing infrastructure). /// OTLP — export via OpenTelemetry Protocol gRPC to Jaeger, Grafana Tempo, etc. /// CONSOLE — write structured spans to stdout (local debugging only). /// NONE — collect but do not export (useful for in-process sampling/metrics). /// /// public string Exporter { get; set; } = "ZIPKIN"; /// OTLP gRPC collector endpoint. Honoured when = OTLP. public string OtlpEndpoint { get; set; } = "http://localhost:4317"; /// Zipkin HTTP endpoint. Honoured when = ZIPKIN. public string ZipkinEndpoint { get; set; } = "http://localhost:9411/api/v2/spans"; /// /// Export processor for the trace pipeline (ZIPKIN and OTLP exporters). Supported values: /// /// Batch (default) — buffers completed spans and flushes on a timer /// () or when the batch fills. Non-blocking /// to the request thread; the OTel SDK default delay is 5000 ms. /// Simple — exports each span synchronously the instant it ends. Adds a /// network round-trip to whatever thread ends the span, but nothing gets buffered. /// /// To watch a long-running request's progress live in Zipkin/Jaeger while it's still in /// flight (e.g. seeing a "query executing" child span appear the moment the query finishes, /// well before PDF rendering completes), give each phase its own child span /// () and lower /// rather than switching to Simple — that keeps exports off the request thread. /// public string TraceExportProcessor { get; set; } = "Batch"; /// /// Milliseconds between batch flushes to the trace exporter when /// is Batch. OTel SDK default is 5000 ms. /// Lower this (e.g. 500) so completed child spans show up in Zipkin/Jaeger within roughly /// that many milliseconds of finishing, instead of waiting up to 5 seconds. /// public int BatchScheduledDelayMilliseconds { get; set; } = 5000; /// /// Head-based trace sampling ratio between 0.0 (never) and 1.0 (always). /// Default 1.0 captures every request — reduce in high-traffic production environments. /// public double SamplingRatio { get; set; } = 1.0; /// /// Enable ASP.NET Core request / response metrics (latency histograms, request counts). /// public bool EnableMetrics { get; set; } = true; /// /// Write a secondary copy of traces to stdout in addition to the primary exporter. /// Useful during development to see spans without running a collector. /// public bool EnableConsoleExporter { get; set; } = false; /// Semantic version reported in the OTel resource descriptor, e.g. "2.1.0". public string ServiceVersion { get; set; } = "1.0.0"; /// /// Deployment environment tag written to every span resource, e.g. /// "Development", "Staging", "Production". /// public string Environment { get; set; } = "Development"; /// /// Attach full exception stack traces to error spans as OTel events. /// Set to false to suppress stack traces in high-security environments. /// public bool RecordExceptions { get; set; } = true; /// /// Maximum characters captured in the db.statement span tag. /// Set to 0 (default) to capture the full SQL with no truncation. /// Set to a positive value (e.g. 2000) to cap long statements in high-traffic production environments. /// public int MaxDbStatementLength { get; set; } = 0; // ── Request / Response payload capture ─────────────────────────────────── /// /// Capture the JSON request body as an http.request.body span tag on the root request span. /// Applies only to requests with Content-Type: application/json. /// Default: true. /// public bool CaptureRequestBody { get; set; } = true; /// /// Maximum bytes to read from the request body when is enabled. /// Content exceeding this limit is captured up to the limit with a "...[truncated]" suffix. /// Default: 8192 (8 KB) — covers typical GB5 DTO payloads with room to spare. /// public int MaxRequestBodyBytes { get; set; } = 8192; // ── Log-to-span bridge ─────────────────────────────────────────────────── /// /// Bridge calls from GB5 application code as span events on the active span. /// Every BLL, DAL, and service log statement appears in the trace timeline automatically — /// no per-class changes are needed anywhere in the codebase. /// Default: true. /// public bool CaptureLogEvents { get; set; } = true; /// /// Minimum for the log-to-span bridge. /// Default: — Debug/Trace entries are excluded from spans. /// public LogLevel LogEventMinLevel { get; set; } = LogLevel.Information; // ── Exception detail capture ───────────────────────────────────────────── /// /// When an unhandled exception escapes to the request tracing middleware, /// enrich the active span with full exception details: type, message, stack trace, /// inner exception chain, correlation ID, and trace/span IDs. /// Default: true. /// public bool CaptureExceptionDetails { get; set; } = true; /// /// Maximum depth of the inner exception chain to capture when /// is enabled. /// Default: 5. /// public int MaxExceptionDepth { get; set; } = 5; // ── Environment-aware sampling ─────────────────────────────────────────── /// /// When true and SamplingRatio is not explicitly set in appsettings, /// the effective sampling ratio is resolved from ASPNETCORE_ENVIRONMENT: /// /// Development → 1.0 (every request) /// QA / Test → 0.5 (50 %) /// UAT / Staging → 0.1 (10 %) /// Production → 0.05 (5 %) /// /// An explicit SamplingRatio value in appsettings always takes precedence. /// public bool UseEnvironmentSamplingDefaults { get; set; } = true; /// /// Returns the recommended sampling ratio for a given ASPNETCORE_ENVIRONMENT value. /// Used by GB5TelemetryExtensions when is true. /// public static double GetEnvironmentSamplingDefault(string? environment) => environment?.ToUpperInvariant() switch { "PRODUCTION" or "PROD" => 0.05, "UAT" or "STAGING" or "PREPROD" => 0.1, "QA" or "TEST" => 0.5, _ => 1.0 // Development, local, unknown — capture all }; }