Documentation
¶
Overview ¶
Package instrumentation provides comprehensive OpenTelemetry instrumentation for the inboxfewer MCP server.
This package enables production-grade observability through:
- OpenTelemetry metrics for HTTP requests, OAuth operations, and Google API calls
- Distributed tracing for request flows and API calls
- Prometheus metrics export via /metrics endpoint on dedicated port
- OTLP export support for modern observability platforms
Metrics ¶
The package exposes the following metric categories:
Server/HTTP Metrics:
- http_requests_total: Counter of HTTP requests by method, path, and status
- http_request_duration_seconds: Histogram of HTTP request durations
- active_sessions: Gauge of active user sessions
Google API Metrics:
- google_api_operations_total: Counter of Google API operations by service, operation, status
- google_api_operation_duration_seconds: Histogram of Google API operation durations
OAuth Authentication Metrics:
- oauth_auth_total: Counter of OAuth authentication events by result
- oauth_token_refresh_total: Counter of token refresh attempts by result
MCP Tool Metrics:
- mcp_tool_invocations_total: Counter of MCP tool invocations by tool name and status
- mcp_tool_duration_seconds: Histogram of MCP tool execution durations
Tracing ¶
Distributed tracing spans are created for:
- HTTP request handling
- MCP tool invocations (tool.<name>)
- Google API calls (google.<service>.<operation>)
- OAuth token operations
Configuration ¶
Instrumentation can be configured via environment variables:
- INSTRUMENTATION_ENABLED: Enable/disable instrumentation (default: true)
- METRICS_EXPORTER: Metrics exporter type (prometheus, otlp, stdout, default: prometheus)
- TRACING_EXPORTER: Tracing exporter type (otlp, stdout, none, default: none)
- OTEL_EXPORTER_OTLP_ENDPOINT: OTLP endpoint for traces/metrics
- OTEL_TRACES_SAMPLER_ARG: Sampling rate (0.0 to 1.0, default: 0.1)
- OTEL_SERVICE_NAME: Service name (default: inboxfewer)
Example Usage ¶
// Initialize instrumentation
provider, err := instrumentation.NewProvider(ctx, instrumentation.Config{
ServiceName: "inboxfewer",
ServiceVersion: "0.1.0",
Enabled: true,
})
if err != nil {
return err
}
defer provider.Shutdown(ctx)
// Get metrics recorder
recorder := provider.Metrics()
// Record an HTTP request
recorder.RecordHTTPRequest(ctx, "POST", "/mcp", 200, time.Since(start))
// Record a Google API operation
recorder.RecordGoogleAPIOperation(ctx, "gmail", "list", "success", time.Since(start))
// Record an MCP tool invocation
recorder.RecordToolInvocation(ctx, "gmail_list_emails", "success", time.Since(start))
Index ¶
- Constants
- func AddSpanEvent(span trace.Span, name string, attrs ...attribute.KeyValue)
- func ExtractUserDomain(email string) string
- func GetSpanID(ctx context.Context) string
- func GetTraceID(ctx context.Context) string
- func SetSpanError(span trace.Span, err error)
- func SetSpanSuccess(span trace.Span)
- func SpanContextString(ctx context.Context) string
- func StartGoogleAPISpan(ctx context.Context, service, operation string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
- func StartSpan(ctx context.Context, name string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
- func StartToolSpan(ctx context.Context, toolName string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
- func TraceIDFromContext(ctx context.Context) stringdeprecated
- type AuditLogger
- type AuditLoggingConfig
- type Config
- type Metrics
- func (m *Metrics) DecrementActiveSessions(ctx context.Context)
- func (m *Metrics) IncrementActiveSessions(ctx context.Context)
- func (m *Metrics) RecordGoogleAPIOperation(ctx context.Context, service, operation, status string, duration time.Duration)
- func (m *Metrics) RecordHTTPRequest(ctx context.Context, method, path string, statusCode int, ...)
- func (m *Metrics) RecordOAuthAuth(ctx context.Context, result string)
- func (m *Metrics) RecordOAuthCrossClientToken(ctx context.Context, result, audience string)
- func (m *Metrics) RecordOAuthTokenRefresh(ctx context.Context, result string)
- func (m *Metrics) RecordSSOTokenInjection(ctx context.Context, result string)
- func (m *Metrics) RecordToolInvocation(ctx context.Context, toolName, status string, duration time.Duration)
- func (m *Metrics) RecordToolInvocationWithAccount(ctx context.Context, toolName, status, account string, duration time.Duration)
- type Provider
- type SpanAttributeBuilder
- func (b *SpanAttributeBuilder) Build() []attribute.KeyValue
- func (b *SpanAttributeBuilder) WithAccount(account string) *SpanAttributeBuilder
- func (b *SpanAttributeBuilder) WithOperation(operation string) *SpanAttributeBuilder
- func (b *SpanAttributeBuilder) WithReadOnly(readOnly bool) *SpanAttributeBuilder
- func (b *SpanAttributeBuilder) WithResource(resourceType, resourceID string) *SpanAttributeBuilder
- func (b *SpanAttributeBuilder) WithService(service string) *SpanAttributeBuilder
- func (b *SpanAttributeBuilder) WithTool(tool string) *SpanAttributeBuilder
- type ToolInvocation
- func (ti *ToolInvocation) Complete(success bool, err error) *ToolInvocation
- func (ti *ToolInvocation) CompleteSuccess() *ToolInvocation
- func (ti *ToolInvocation) CompleteWithError(err error) *ToolInvocation
- func (ti *ToolInvocation) LogAttrs() []slog.Attr
- func (ti *ToolInvocation) LogAuditAttrs() []slog.Attr
- func (ti *ToolInvocation) Status() string
- func (ti *ToolInvocation) UserDomain() string
- func (ti *ToolInvocation) WithAccount(account string) *ToolInvocation
- func (ti *ToolInvocation) WithService(serviceName, operation string) *ToolInvocation
- func (ti *ToolInvocation) WithSpanContext(ctx context.Context) *ToolInvocation
- func (ti *ToolInvocation) WithUser(email string) *ToolInvocation
Constants ¶
const ( OperationList = "list" OperationGet = "get" OperationCreate = "create" OperationUpdate = "update" OperationDelete = "delete" OperationSend = "send" OperationSearch = "search" )
Common operation types for Google API metrics. Status, OAuth, and Service constants are defined in config.go.
const ( // Status values StatusSuccess = "success" StatusError = "error" StatusUnknown = "unknown" // OAuth result values OAuthResultSuccess = "success" OAuthResultFailure = "failure" OAuthResultExpired = "expired" // Google service names ServiceGmail = "gmail" ServiceCalendar = "calendar" ServiceDrive = "drive" ServiceDocs = "docs" ServiceMeet = "meet" ServiceTasks = "tasks" // Exporter types ExporterPrometheus = "prometheus" ExporterOTLP = "otlp" ExporterStdout = "stdout" ExporterNone = "none" // Metric recording intervals DefaultMetricInterval = 10 * time.Second )
Constants for metric label values.
const ( // SSOInjectionResultSuccess indicates SSO token was successfully injected SSOInjectionResultSuccess = "sso_success" // SSOInjectionResultStored indicates token was stored in token store (non-SSO path) SSOInjectionResultStored = "stored" // SSOInjectionResultNoUser indicates no authenticated user in context SSOInjectionResultNoUser = "no_user" // SSOInjectionResultNoToken indicates no access token header present SSOInjectionResultNoToken = "no_token" // SSOInjectionResultStoreFailed indicates token store operation failed SSOInjectionResultStoreFailed = "store_failed" )
SSO token injection result constants
const ( // SpanAttrTool is the MCP tool name attribute. SpanAttrTool = "mcp.tool" // SpanAttrService is the Google service name attribute. SpanAttrService = "google.service" // SpanAttrOperation is the operation type attribute. SpanAttrOperation = "google.operation" // SpanAttrAccount is the user account/email attribute. SpanAttrAccount = "mcp.account" // SpanAttrStatus is the operation status attribute. SpanAttrStatus = "mcp.status" // SpanAttrResourceID is the resource identifier (email ID, event ID, etc.). SpanAttrResourceID = "mcp.resource_id" // SpanAttrResourceType is the resource type (email, event, file, etc.). SpanAttrResourceType = "mcp.resource_type" // SpanAttrReadOnly indicates if the operation is read-only. SpanAttrReadOnly = "mcp.read_only" )
Span attribute keys for operations.
const TracerName = "github.com/teemow/inboxfewer"
TracerName is the default tracer name for the inboxfewer package.
Variables ¶
This section is empty.
Functions ¶
func AddSpanEvent ¶
AddSpanEvent adds an event to the span with optional attributes.
func ExtractUserDomain ¶
ExtractUserDomain extracts the domain part from an email address. This reduces cardinality by using the domain instead of the full email. Returns "unknown" for invalid or empty emails to ensure metric labels always have a value.
Example:
ExtractUserDomain("jane@example.com") // "example.com"
ExtractUserDomain("user@gmail.com") // "gmail.com"
ExtractUserDomain("invalid") // "unknown"
ExtractUserDomain("") // "unknown"
func GetSpanID ¶
GetSpanID returns the span ID from the current span in context. Returns empty string if no valid span is present.
func GetTraceID ¶
GetTraceID returns the trace ID from the current span in context. Returns empty string if no valid span is present.
func SetSpanError ¶
SetSpanError records an error on the span and sets the status to error.
func SetSpanSuccess ¶
SetSpanSuccess sets the span status to OK.
func SpanContextString ¶
SpanContextString returns a human-readable trace context string. Format: "trace_id=X span_id=Y" or empty string if no valid context.
func StartGoogleAPISpan ¶
func StartGoogleAPISpan(ctx context.Context, service, operation string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
StartGoogleAPISpan starts a span for Google API operations. Includes service and operation attributes.
func StartSpan ¶
func StartSpan(ctx context.Context, name string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
StartSpan starts a new span with the given name and attributes. Returns the context with the span and the span itself. The caller is responsible for ending the span with defer span.End().
func StartToolSpan ¶
func StartToolSpan(ctx context.Context, toolName string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
StartToolSpan starts a span for an MCP tool invocation. Automatically adds tool name and sets appropriate span kind.
func TraceIDFromContext
deprecated
Types ¶
type AuditLogger ¶
type AuditLogger struct {
// contains filtered or unexported fields
}
AuditLogger provides structured audit logging for tool invocations. It wraps slog.Logger with convenience methods for logging tool operations.
func NewAuditLogger ¶
func NewAuditLogger(logger *slog.Logger) *AuditLogger
NewAuditLogger creates a new AuditLogger with the given slog.Logger. By default, PII is not included in logs (anonymized identifiers are used instead).
func NewAuditLoggerWithConfig ¶
func NewAuditLoggerWithConfig(logger *slog.Logger, config AuditLoggingConfig) *AuditLogger
NewAuditLoggerWithConfig creates a new AuditLogger with the given configuration.
func (*AuditLogger) LogToolAudit ¶
func (al *AuditLogger) LogToolAudit(ti *ToolInvocation)
LogToolAudit logs a tool invocation with full audit details. This includes PII (full email addresses) for compliance/audit purposes. SECURITY: Ensure audit logs are routed to secure storage with appropriate access controls.
Note: This method respects the enabled flag but always includes PII when called, regardless of the IncludePII configuration. Use LogToolInvocation for configuration-aware logging.
func (*AuditLogger) LogToolInvocation ¶
func (al *AuditLogger) LogToolInvocation(ti *ToolInvocation)
LogToolInvocation logs a tool invocation using the standard log attributes. This is suitable for general operational logging with cardinality controls. If the logger is configured with IncludePII, full user emails are logged; otherwise, only domain-based anonymized identifiers are used.
func (*AuditLogger) SetEnabled ¶
func (al *AuditLogger) SetEnabled(enabled bool)
SetEnabled sets whether audit logging is enabled.
func (*AuditLogger) SetIncludePII ¶
func (al *AuditLogger) SetIncludePII(include bool)
SetIncludePII sets whether to include full email addresses in audit logs.
type AuditLoggingConfig ¶
type AuditLoggingConfig struct {
// Enabled determines if audit logging is active (default: true)
// Audit logs contain full PII (user emails) and should be routed to secure storage.
Enabled bool
// IncludePII controls whether to include full email addresses in audit logs.
// When false (default), only anonymized user identifiers are logged.
// When true, full email addresses are included for compliance/audit purposes.
// SECURITY: Ensure audit logs are stored securely with appropriate access controls.
IncludePII bool
// LogLevel sets the slog level for audit log messages (default: INFO).
// Options: "debug", "info", "warn", "error"
// Note: Audit events are always logged regardless of this level.
LogLevel string
}
AuditLoggingConfig holds configuration for audit logging.
type Config ¶
type Config struct {
// ServiceName is the name of the service (default: inboxfewer)
ServiceName string
// ServiceVersion is the version of the service
ServiceVersion string
// ServiceInstanceID is the unique instance identifier (default: hostname)
// In Kubernetes, this is typically the pod name
ServiceInstanceID string
// K8sNamespace is the Kubernetes namespace where the service is running
K8sNamespace string
// K8sPodName is the Kubernetes pod name
K8sPodName string
// Enabled determines if instrumentation is active (default: true)
// Set to false via INSTRUMENTATION_ENABLED=false to disable metrics and tracing
Enabled bool
// MetricsExporter specifies the metrics exporter type
// Options: "prometheus", "otlp", "stdout" (default: "prometheus")
MetricsExporter string
// TracingExporter specifies the tracing exporter type
// Options: "otlp", "stdout", "none" (default: "none")
TracingExporter string
// OTLPEndpoint is the OTLP collector endpoint
// Example: "localhost:4318" (without protocol prefix)
OTLPEndpoint string
// OTLPInsecure controls whether to use insecure HTTP for OTLP export
// When false (default), uses TLS for secure transport
// Set to true only for local development or testing with unencrypted endpoints
// WARNING: Never use insecure transport in production - traces may contain
// sensitive metadata and should be encrypted in transit
OTLPInsecure bool
// TraceSamplingRate is the sampling rate for traces (0.0 to 1.0, default: 0.1)
TraceSamplingRate float64
// PrometheusEndpoint is the path for the Prometheus metrics endpoint (default: "/metrics")
PrometheusEndpoint string
// DetailedLabels controls whether high-cardinality labels are included.
// When false (default), only essential labels are included.
// When true, additional labels like specific email addresses may be added.
// For production, keep detailedLabels disabled to avoid cardinality explosion.
DetailedLabels bool
// AuditLogging configures audit logging behavior.
AuditLogging AuditLoggingConfig
}
Config holds the configuration for OpenTelemetry instrumentation.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config with sensible defaults based on environment variables.
type Metrics ¶
type Metrics struct {
// contains filtered or unexported fields
}
Metrics provides methods for recording observability metrics.
func NewMetrics ¶
NewMetrics creates a new Metrics instance with all metrics initialized. The detailedLabels parameter controls whether high-cardinality labels are included.
func (*Metrics) DecrementActiveSessions ¶
DecrementActiveSessions decrements the active sessions counter.
func (*Metrics) IncrementActiveSessions ¶
IncrementActiveSessions increments the active sessions counter.
func (*Metrics) RecordGoogleAPIOperation ¶
func (m *Metrics) RecordGoogleAPIOperation(ctx context.Context, service, operation, status string, duration time.Duration)
RecordGoogleAPIOperation records a Google API operation with service, operation, status, and duration.
Parameters:
- service: Google service name (gmail, calendar, drive, docs, meet, tasks)
- operation: Operation type (list, get, create, update, delete, send, etc.)
- status: Result status ("success" or "error")
- duration: Time taken for the operation
func (*Metrics) RecordHTTPRequest ¶
func (m *Metrics) RecordHTTPRequest(ctx context.Context, method, path string, statusCode int, duration time.Duration)
RecordHTTPRequest records an HTTP request with method, path, status code, and duration.
func (*Metrics) RecordOAuthAuth ¶
RecordOAuthAuth records an OAuth authentication attempt with result. Result should be one of: "success", "failure"
func (*Metrics) RecordOAuthCrossClientToken ¶ added in v0.0.46
RecordOAuthCrossClientToken records a cross-client OAuth token event for SSO monitoring. This tracks when tokens from trusted upstream clients (aggregators) are processed.
Parameters:
- result: "accepted" when token from TrustedAudiences is validated, "rejected" when audience not trusted
- audience: The token's audience (client ID) for debugging (optional, only included if detailedLabels enabled)
func (*Metrics) RecordOAuthTokenRefresh ¶
RecordOAuthTokenRefresh records an OAuth token refresh attempt with result. Result should be one of: "success", "failure", "expired"
func (*Metrics) RecordSSOTokenInjection ¶ added in v0.0.51
RecordSSOTokenInjection records an SSO access token injection attempt. This tracks the different outcomes of the SSOAccessTokenMiddleware.
Parameters:
- result: One of the SSOInjectionResult* constants indicating the outcome
func (*Metrics) RecordToolInvocation ¶
func (m *Metrics) RecordToolInvocation(ctx context.Context, toolName, status string, duration time.Duration)
RecordToolInvocation records an MCP tool invocation with tool name, status, and duration.
Parameters:
- toolName: Name of the MCP tool (e.g., "gmail_list_emails", "calendar_create_event")
- status: Result status ("success" or "error")
- duration: Time taken for the tool execution
func (*Metrics) RecordToolInvocationWithAccount ¶
func (m *Metrics) RecordToolInvocationWithAccount(ctx context.Context, toolName, status, account string, duration time.Duration)
RecordToolInvocationWithAccount records an MCP tool invocation with account info. This is the detailed version that includes account information when detailedLabels is enabled.
Parameters:
- toolName: Name of the MCP tool
- status: Result status ("success" or "error")
- account: User account/email (only included if detailedLabels is true)
- duration: Time taken for the tool execution
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider encapsulates OpenTelemetry meter and tracer providers.
func NewProvider ¶
NewProvider creates a new OpenTelemetry provider with the given configuration.
func (*Provider) Metrics ¶
Metrics returns the metrics recorder for recording observability metrics.
func (*Provider) PrometheusHandler ¶
func (p *Provider) PrometheusHandler() interface{}
PrometheusHandler returns an HTTP handler for the Prometheus metrics endpoint. Returns nil if Prometheus exporter is not configured.
type SpanAttributeBuilder ¶
type SpanAttributeBuilder struct {
// contains filtered or unexported fields
}
SpanAttributeBuilder helps construct OpenTelemetry span attributes with consistent naming.
func NewSpanAttributeBuilder ¶
func NewSpanAttributeBuilder() *SpanAttributeBuilder
NewSpanAttributeBuilder creates a new SpanAttributeBuilder.
func (*SpanAttributeBuilder) Build ¶
func (b *SpanAttributeBuilder) Build() []attribute.KeyValue
Build returns the constructed attributes.
func (*SpanAttributeBuilder) WithAccount ¶
func (b *SpanAttributeBuilder) WithAccount(account string) *SpanAttributeBuilder
WithAccount adds the user account attribute.
func (*SpanAttributeBuilder) WithOperation ¶
func (b *SpanAttributeBuilder) WithOperation(operation string) *SpanAttributeBuilder
WithOperation adds the operation type attribute.
func (*SpanAttributeBuilder) WithReadOnly ¶
func (b *SpanAttributeBuilder) WithReadOnly(readOnly bool) *SpanAttributeBuilder
WithReadOnly adds the read-only indicator attribute.
func (*SpanAttributeBuilder) WithResource ¶
func (b *SpanAttributeBuilder) WithResource(resourceType, resourceID string) *SpanAttributeBuilder
WithResource adds resource attributes.
func (*SpanAttributeBuilder) WithService ¶
func (b *SpanAttributeBuilder) WithService(service string) *SpanAttributeBuilder
WithService adds the Google service name attribute.
func (*SpanAttributeBuilder) WithTool ¶
func (b *SpanAttributeBuilder) WithTool(tool string) *SpanAttributeBuilder
WithTool adds the MCP tool name attribute.
type ToolInvocation ¶
type ToolInvocation struct {
// Tool name
Tool string
// User identity (from OAuth)
UserEmail string
// Target information for Google services
Account string // Account name (default, work, personal)
ServiceName string // Google service (gmail, calendar, drive, docs, meet, tasks)
Operation string // Operation type (list, get, create, update, delete, send)
// Execution details
StartTime time.Time
Duration time.Duration
Success bool
Error string
// Tracing context
TraceID string
SpanID string
}
ToolInvocation captures all information about a tool invocation for audit logging. This provides a comprehensive audit trail for all MCP tool calls.
Privacy Considerations ¶
The UserEmail field contains PII. When logging, consider:
- Using UserDomain() to get only the domain for metrics/general logs
- Only logging full email in audit-specific log streams
- Ensuring audit logs have appropriate access controls
func NewToolInvocation ¶
func NewToolInvocation(tool string) *ToolInvocation
NewToolInvocation creates a new ToolInvocation with timing started. Call Complete() when the tool operation finishes.
func (*ToolInvocation) Complete ¶
func (ti *ToolInvocation) Complete(success bool, err error) *ToolInvocation
Complete marks the invocation as completed and calculates duration. Returns the same ToolInvocation for method chaining.
func (*ToolInvocation) CompleteSuccess ¶
func (ti *ToolInvocation) CompleteSuccess() *ToolInvocation
CompleteSuccess marks the invocation as successful.
func (*ToolInvocation) CompleteWithError ¶
func (ti *ToolInvocation) CompleteWithError(err error) *ToolInvocation
CompleteWithError marks the invocation as failed with the given error.
func (*ToolInvocation) LogAttrs ¶
func (ti *ToolInvocation) LogAttrs() []slog.Attr
LogAttrs returns slog attributes for structured logging. This provides a consistent set of fields for all tool invocation logs.
Cardinality ¶
This function uses cardinality-controlled values (user_domain) for metrics-compatible logging. For full audit logging, use LogAuditAttrs.
func (*ToolInvocation) LogAuditAttrs ¶
func (ti *ToolInvocation) LogAuditAttrs() []slog.Attr
LogAuditAttrs returns slog attributes for full audit logging. This includes the full user email for compliance/audit purposes.
Security Warning ¶
This method includes PII (full email). Ensure audit logs are:
- Stored securely with appropriate access controls
- Not exposed to general monitoring dashboards
- Retained according to compliance requirements
func (*ToolInvocation) Status ¶
func (ti *ToolInvocation) Status() string
Status returns "success" or "error" based on the Success field.
func (*ToolInvocation) UserDomain ¶
func (ti *ToolInvocation) UserDomain() string
UserDomain returns the domain portion of the user's email for lower-cardinality logging.
func (*ToolInvocation) WithAccount ¶
func (ti *ToolInvocation) WithAccount(account string) *ToolInvocation
WithAccount sets the Google account name.
func (*ToolInvocation) WithService ¶
func (ti *ToolInvocation) WithService(serviceName, operation string) *ToolInvocation
WithService sets the Google service and operation.
func (*ToolInvocation) WithSpanContext ¶
func (ti *ToolInvocation) WithSpanContext(ctx context.Context) *ToolInvocation
WithSpanContext extracts trace context from the current span.
func (*ToolInvocation) WithUser ¶
func (ti *ToolInvocation) WithUser(email string) *ToolInvocation
WithUser sets the user identity information.