blob: b3046519b5a59a66272c197c3701140935057446 [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package log
import (
"errors"
"time"
)
// Property represents a key value pair that was stored on the context.
type Property struct {
Name string
Value interface{}
}
// Record represents the gathered information for a single entry in a log.
type Record struct {
TimeStamp time.Time
Severity Severity
Message interface{} // The message text.
Detail string // The message detail text.
Chain *Record
Cause error // The cause if present.
Tag string
Raw *string
Trace *Chain
StackTrace StackTrace
StackFilter StackFilter
Properties []Property // The set of extra properties
}
// Recorder is the type for functions that build Record objects from Context ones.
// It will be handed a basic Record to fill in, the record will be partially complete.
// It will be invoked once per log record in the stream, but it is safe to chain them.
type Recorder func(ctx Context, r *Record)
// GetRecorder gets the active Handler for this context.
func GetRecorder(ctx Context) Recorder {
r, _ := ctx.Value(recorderKey).(Recorder)
return r
}
// Recorder returns a new Context with the given Handler set on it.
func (ctx logContext) Recorder(r Recorder) Context {
return ctx.setValue(recorderKey, r)
}
// Record returns a log record from the current builder context with the supplied message.
func (ctx logContext) Record(msg interface{}) Record {
r := Record{
TimeStamp: time.Now(),
Severity: GetSeverity(ctx),
Message: msg,
Detail: GetDetail(ctx),
Cause: GetCause(ctx),
Tag: GetTag(ctx),
Trace: GetTrace(ctx),
StackFilter: GetStackFilter(ctx),
Properties: []Property{},
}
if raw, ok := ctx.Value(rawKey).(string); ok {
r.Raw = &raw
}
if chain, ok := r.Cause.(errorRecord); ok {
r.Cause = nil
r.Chain = (*Record)(&chain)
}
r.AddProperties(ctx)
hook := GetRecorder(ctx)
if hook != nil {
hook(ctx, &r)
}
return r
}
// AddProperties collects all keyed properties from the context and adds them to r.Properties
func (r *Record) AddProperties(ctx logContext) {
seen := map[string]struct{}{}
for it, _ := ctx.Value(keysKey).(*Chain); it != nil; it = it.Next {
key := it.Value.(string)
if _, found := seen[key]; !found {
seen[key] = struct{}{}
r.Properties = append(r.Properties, Property{Name: key, Value: ctx.Value(key)})
}
}
}
// List collects log records.
type List []Record
// ErrorLimit is thrown when an error list reaches capacity.
var ErrorLimit = errors.New("Error limit reached")
// CollectAll inserts a handler into ctx that collects records into the returned list.
func (l *List) CollectAll() Handler {
return func(r Record) {
*l = append(*l, r)
}
}
// Collect inserts a handler into ctx that collects records into the returned list.
// If it reaches the specified limit of errors, it will panic with ErrorLimit.
func (l *List) Collect(limit int) Handler {
return func(r Record) {
*l = append(*l, r)
if len(*l) >= limit {
panic(ErrorLimit)
}
}
}