Skip to content

Commit

Permalink
log: Add EmitEvent and EnabledEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
pellared committed Dec 4, 2024
1 parent 3f68bca commit 864e0e0
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 3 deletions.
14 changes: 14 additions & 0 deletions log/internal/global/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,20 @@ func (l *logger) Enabled(ctx context.Context, param log.EnabledParameters) bool
return enabled
}

func (l *logger) EmitEvent(ctx context.Context, eventName string, e log.Event) {
if del, ok := l.delegate.Load().(log.Logger); ok {
del.EmitEvent(ctx, eventName, e)
}
}

func (l *logger) EnabledEvent(ctx context.Context, eventName string, param log.EnabledEventParameters) bool {
var enabled bool
if del, ok := l.delegate.Load().(log.Logger); ok {
enabled = del.EnabledEvent(ctx, eventName, param)
}
return enabled
}

func (l *logger) setDelegate(provider log.LoggerProvider) {
l.delegate.Store(provider.Logger(l.name, l.options...))
}
2 changes: 1 addition & 1 deletion log/internal/global/log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (p *testLoggerProvider) Logger(name string, _ ...log.LoggerOption) log.Logg
}

type testLogger struct {
embedded.Logger
log.Logger

emitN, enabledN int
}
Expand Down
39 changes: 37 additions & 2 deletions log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ type Logger interface {
// Is should not be used for writing instrumentation.
Emit(ctx context.Context, record Record)

// Enabled returns whether the Logger emits for the given context and
// param.
// Enabled returns whether the Logger emits a log record for the given
// context and param.
//
// The passed param is likely to be a partial record with only the
// bridge-relevant information being provided (e.g a param with only the
Expand All @@ -57,6 +57,36 @@ type Logger interface {
// Notice: Enabled is intended to be used by log bridges.
// Is should not be used for writing instrumentation.
Enabled(ctx context.Context, param EnabledParameters) bool

// EmitEvent emits an event.
//
// The event may be held by the implementation. Callers should not mutate
// the event after passed.
//
// Implementations of this method need to be safe for a user to call
// concurrently.
//
// Notice: EmitEvent is intended to be used for writing instrumentation.
EmitEvent(ctx context.Context, eventName string, event Event)

// EnabledEvent returns whether the Logger emits an event for the given
// context, eventName, and param.
//
// The returned value will be true when the Logger will emit for the
// provided context and param, and will be false if the Logger will not
// emit. The returned value may be true or false in an indeterminate state.
// An implementation should default to returning true for an indeterminate
// state, but may return false if valid reasons in particular circumstances
// exist (e.g. performance, correctness).
//
// The param should not be held by the implementation. A copy should be
// made if the record needs to be held after the call returns.
//
// Implementations of this method need to be safe for a user to call
// concurrently.
//
// Notice: EnabledEvent is intended to be used for writing instrumentation.
EnabledEvent(ctx context.Context, eventName string, param EnabledEventParameters) bool
}

// LoggerOption applies configuration options to a [Logger].
Expand Down Expand Up @@ -140,3 +170,8 @@ func WithSchemaURL(schemaURL string) LoggerOption {
type EnabledParameters struct {
Severity Severity
}

// EnabledEventParameters represents payload for [Logger]'s Enabled method.
type EnabledEventParameters struct {
Severity Severity
}
37 changes: 37 additions & 0 deletions log/logtest/recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ type ScopeRecords struct {
// Records are the log records, and their associated context this
// instrumentation scope recorded.
Records []EmittedRecord

// Events are the events, and their associated context this
// instrumentation scope recorded.
Events []EmittedEvent
}

// EmittedRecord holds a log record the instrumentation received, alongside its
Expand All @@ -88,6 +92,25 @@ func (rwc EmittedRecord) Context() context.Context {
return rwc.ctx
}

// EmittedEvent holds an event the instrumentation received, alongside its
// context and event name.
type EmittedEvent struct {
log.Event

ctx context.Context
eventName string
}

// Context provides the context emitted with the event.
func (rwc EmittedEvent) Context() context.Context {
return rwc.ctx
}

// EventName provides the context emitted with the event.
func (rwc EmittedEvent) EventName() string {
return rwc.eventName
}

// Recorder is a recorder that stores all received log records
// in-memory.
type Recorder struct {
Expand Down Expand Up @@ -182,3 +205,17 @@ func (l *logger) Reset() {

l.scopeRecord.Records = nil
}

// Enabled indicates whether a specific event should be stored.
func (l *logger) EnabledEvent(ctx context.Context, eventName string, opts log.EnabledEventParameters) bool {
// TODO:
return true
}

// EmitEvent stores the event.
func (l *logger) EmitEvent(ctx context.Context, eventName string, event log.Event) {
l.mu.Lock()
defer l.mu.Unlock()

l.scopeRecord.Events = append(l.scopeRecord.Events, EmittedEvent{event, ctx, eventName})
}
6 changes: 6 additions & 0 deletions log/noop/noop.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,9 @@ func (Logger) Emit(context.Context, log.Record) {}

// Enabled returns false. No log records are ever emitted.
func (Logger) Enabled(context.Context, log.EnabledParameters) bool { return false }

// EmitEvent does nothing.
func (Logger) EmitEvent(context.Context, string, log.Event) {}

// EnabledEvent returns false. No events are ever emitted.
func (Logger) EnabledEvent(context.Context, string, log.EnabledEventParameters) bool { return false }
60 changes: 60 additions & 0 deletions sdk/log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,31 @@ func (l *logger) Enabled(ctx context.Context, param log.EnabledParameters) bool
return len(l.provider.processors) > len(fltrs) || anyEnabled(ctx, param, fltrs)
}

func (l *logger) EmitEvent(ctx context.Context, eventName string, r log.Event) {
newRecord := l.newEvent(ctx, eventName, r)
for _, p := range l.provider.processors {
if err := p.OnEmit(ctx, &newRecord); err != nil {
otel.Handle(err)
}
}
}

// EnabledEvent returns true if at least one Processor held by the LoggerProvider
// that created the logger will process param for the provided context and param.
//
// If it is not possible to definitively determine the param will be
// processed, true will be returned by default. A value of false will only be
// returned if it can be positively verified that no Processor will process.
func (l *logger) EnabledEvent(ctx context.Context, eventName string, param log.EnabledEventParameters) bool {
fltrs := l.provider.filterProcessors()
// If there are more Processors than FilterProcessors we cannot be sure
// that all Processors will drop the record. Therefore, return true.
//
// If all Processors are FilterProcessors, check if any is enabled.

return len(l.provider.processors) > len(fltrs) || anyEnabled(ctx, log.EnabledParameters(param), fltrs)
}

func anyEnabled(ctx context.Context, param log.EnabledParameters, fltrs []x.FilterProcessor) bool {
for _, f := range fltrs {
if f.Enabled(ctx, param) {
Expand Down Expand Up @@ -101,3 +126,38 @@ func (l *logger) newRecord(ctx context.Context, r log.Record) Record {

return newRecord
}

func (l *logger) newEvent(ctx context.Context, name string, e log.Event) Record {
sc := trace.SpanContextFromContext(ctx)

newRecord := Record{
eventName: name,

timestamp: e.Timestamp(),
observedTimestamp: e.ObservedTimestamp(),
severity: e.Severity(),
severityText: e.SeverityText(),
body: e.Body(),

traceID: sc.TraceID(),
spanID: sc.SpanID(),
traceFlags: sc.TraceFlags(),

resource: l.provider.resource,
scope: &l.instrumentationScope,
attributeValueLengthLimit: l.provider.attributeValueLengthLimit,
attributeCountLimit: l.provider.attributeCountLimit,
}

// This field SHOULD be set once the event is observed by OpenTelemetry.
if newRecord.observedTimestamp.IsZero() {
newRecord.observedTimestamp = now()
}

e.WalkAttributes(func(kv log.KeyValue) bool {
newRecord.AddAttributes(kv)
return true
})

return newRecord
}
12 changes: 12 additions & 0 deletions sdk/log/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type Record struct {
// Do not embed the log.Record. Attributes need to be overwrite-able and
// deep-copying needs to be possible.

eventName string

timestamp time.Time
observedTimestamp time.Time
severity log.Severity
Expand Down Expand Up @@ -104,6 +106,16 @@ func (r *Record) setDropped(n int) {
r.dropped = n
}

// EventName returns the event name.
func (r *Record) EventName() string {
return r.eventName
}

// SetEventName sets the event name.
func (r *Record) SetEventName(s string) {
r.eventName = s
}

// Timestamp returns the time when the log record occurred.
func (r *Record) Timestamp() time.Time {
return r.timestamp
Expand Down

0 comments on commit 864e0e0

Please sign in to comment.