Documentation
¶
Overview ¶
Package sink provides a generic record-and-close interface for writing JSON-marshalable payloads to a destination, the concrete implementations (file, nop) the rest of the codebase consumes, and the OTel decorator that re-encodes any payload as OTLP/JSON log records on the way to a sink.
The interface is deliberately payload-agnostic: callers pass any value that json.Marshal can handle, and the sink takes responsibility for serialisation, transport, and durability semantics. This lets unrelated subsystems (audit, future activity/telemetry channels, etc) share the same plumbing -- file rotation, GC, alternate transports plug in once and benefit everyone.
Index ¶
Constants ¶
const ( OTelSeverityInfo = 9 OTelSeverityError = 17 // DefaultOTelSchemaURL pins the semantic conventions release the stable // attributes (service.*, error.*) are taken from. DefaultOTelSchemaURL = "https://opentelemetry.io/schemas/1.44.0" )
OTel log severity numbers per the OpenTelemetry logs data model.
Variables ¶
This section is empty.
Functions ¶
func OTelRandomID ¶ added in v0.11.669
OTelRandomID returns n random bytes as lowercase hex (16 bytes for a trace id, 8 for a span or call id).
Types ¶
type FileConfig ¶
type FileConfig struct {
// Path is the absolute or relative path to the log file. When set,
// Dir and DefaultFilename are ignored.
Path string `json:"path,omitempty" yaml:"path,omitempty"`
// Dir is the directory in which the sink writes the log when Path is
// empty. Must be set in that case. Relative directories are resolved
// against cwd at NewFileSink time.
Dir string `json:"dir,omitempty" yaml:"dir,omitempty"`
// MaxSizeMB triggers rotation when the file grows past this size.
// Zero means lumberjack's default (100 MB).
MaxSizeMB int `json:"max_size_mb,omitempty" yaml:"max_size_mb,omitempty"`
// MaxBackups is the number of rotated files to keep.
// Zero means keep all (lumberjack default).
MaxBackups int `json:"max_backups,omitempty" yaml:"max_backups,omitempty"`
// MaxAgeDays is the maximum age in days for rotated files.
// Zero means no age-based deletion (lumberjack default).
MaxAgeDays int `json:"max_age_days,omitempty" yaml:"max_age_days,omitempty"`
// DefaultFilename is consulted when Path is empty. It returns just the
// basename; the sink joins it with Dir. When nil, a generic
// "sink_<RFC3339-utc-second>.log" filename is used. Made a function so
// callers can encode their own naming convention (eg
// "stackql_mcp_server_<timestamp>.log") without bringing the format
// string into the sink package.
DefaultFilename func(time.Time) string `json:"-" yaml:"-"`
}
FileConfig is the on-disk file sink configuration.
Either Path (a complete file path) or Dir (a directory in which the sink will pick a filename via DefaultFilename) must be set. NewFileSink errors when both are empty; the sink never silently picks a directory of its own. The caller -- not the sink -- owns the "where do logs land" decision.
type OTelAnyValue ¶ added in v0.11.669
type OTelAnyValue struct {
StringValue *string `json:"stringValue,omitempty"`
IntValue *string `json:"intValue,omitempty"`
DoubleValue *float64 `json:"doubleValue,omitempty"`
BoolValue *bool `json:"boolValue,omitempty"`
}
OTelAnyValue is the OTLP/JSON encoding of an attribute value; exactly one field is set.
type OTelAttribute ¶ added in v0.11.669
type OTelAttribute struct {
Key string `json:"key"`
Value OTelAnyValue `json:"value"`
}
OTelAttribute is one OTLP/JSON key/value pair.
func OTelAttributesFromJSON ¶ added in v0.11.669
func OTelAttributesFromJSON(raw []byte) ([]OTelAttribute, bool)
OTelAttributesFromJSON maps a JSON object's top-level fields to typed attributes in key order; nested values are carried as JSON strings and nulls as empty strings (dropped on encode). ok is false when raw is not an object.
func OTelBool ¶ added in v0.11.669
func OTelBool(key string, v bool) OTelAttribute
func OTelDouble ¶ added in v0.11.669
func OTelDouble(key string, v float64) OTelAttribute
func OTelInt ¶ added in v0.11.669
func OTelInt(key string, v int64) OTelAttribute
func OTelString ¶ added in v0.11.669
func OTelString(key, v string) OTelAttribute
OTelString / OTelInt / OTelDouble / OTelBool build typed attributes.
type OTelLogRecord ¶ added in v0.11.669
type OTelLogRecord struct {
Time time.Time
Severity int
Body string
// Attributes are emitted in order; empty string values are dropped.
Attributes []OTelAttribute
// TraceParent is a caller-supplied W3C traceparent, honoured when well
// formed; otherwise one trace id is generated per CorrelationKey (e.g. a
// session) so related records correlate.
TraceParent string
CorrelationKey string
}
OTelLogRecord is one log record before envelope decoration; the sink adds the resource, scope, observed time, and trace/span ids.
type OTelLogsData ¶ added in v0.11.669
type OTelLogsData struct {
ResourceLogs []OTelResourceLogs `json:"resourceLogs"`
}
OTelLogsData is one OTLP/JSON logs export payload; the file sink writes one per line, the shape the collector's otlp_json_file receiver ingests.
type OTelRecorder ¶ added in v0.11.669
type OTelRecorder interface {
OTelLogRecords() []OTelLogRecord
}
OTelRecorder is implemented by payloads that map themselves onto log records. Payloads that do not implement it are decorated generically: the JSON object's top-level fields become attributes and the whole object the body.
type OTelResource ¶ added in v0.11.669
type OTelResource struct {
ServiceName string
ServiceVersion string
// Attributes are appended after service.name / service.version.
Attributes []OTelAttribute
}
OTelResource identifies the emitting service.
type OTelResourceLogs ¶ added in v0.11.669
type OTelResourceLogs struct {
Resource otelResource `json:"resource"`
ScopeLogs []OTelScopeLogs `json:"scopeLogs"`
SchemaURL string `json:"schemaUrl"`
}
OTelResourceLogs is an OTLP/JSON ResourceLogs.
type OTelScope ¶ added in v0.11.669
OTelScope identifies the instrumentation that produced the records; use Version for the emitted attribute schema so consumers can pin against it.
type OTelScopeLogs ¶ added in v0.11.669
type OTelScopeLogs struct {
Scope otelInstrumentationScope `json:"scope"`
LogRecords []OTelWireLogRecord `json:"logRecords"`
SchemaURL string `json:"schemaUrl"`
}
OTelScopeLogs is an OTLP/JSON ScopeLogs.
type OTelWireLogRecord ¶ added in v0.11.669
type OTelWireLogRecord struct {
TimeUnixNano string `json:"timeUnixNano"`
ObservedTimeUnixNano string `json:"observedTimeUnixNano"`
SeverityNumber int `json:"severityNumber"`
SeverityText string `json:"severityText"`
Body OTelAnyValue `json:"body"`
Attributes []OTelAttribute `json:"attributes"`
TraceID string `json:"traceId"`
SpanID string `json:"spanId"`
}
OTelWireLogRecord is an OTLP/JSON LogRecord.
type Sink ¶
type Sink interface {
// Record serialises and writes one payload. Errors include transport
// failures (full disk, broken pipe, etc) and marshalling failures.
Record(ctx context.Context, payload any) error
// Close flushes any buffered state and releases the underlying resource.
Close() error
}
Sink is the generic destination contract. Implementations must be safe for concurrent calls from multiple goroutines.
func NewFileSink ¶
func NewFileSink(cfg FileConfig) (Sink, error)
NewFileSink constructs a file-backed sink. Exactly one of cfg.Path or cfg.Dir must be supplied:
- cfg.Path set: used as-is. Relative paths are resolved against cwd.
- cfg.Path empty + cfg.Dir set: the sink picks the basename via cfg.DefaultFilename (or the package-default fallback) and joins it with Dir.
The resolved absolute path is logged to stderr at startup so operators can find the file later.
func NewOTelSink ¶ added in v0.11.669
func NewOTelSink(inner Sink, resource OTelResource, scope OTelScope) Sink
NewOTelSink wraps inner so every recorded payload is written as OTLP/JSON.