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
};
}