1package zerolog
2
3import (
4	"io/ioutil"
5	"math"
6	"net"
7	"time"
8)
9
10// Context configures a new sub-logger with contextual fields.
11type Context struct {
12	l Logger
13}
14
15// Logger returns the logger with the context previously set.
16func (c Context) Logger() Logger {
17	return c.l
18}
19
20// Fields is a helper function to use a map to set fields using type assertion.
21func (c Context) Fields(fields map[string]interface{}) Context {
22	c.l.context = appendFields(c.l.context, fields)
23	return c
24}
25
26// Dict adds the field key with the dict to the logger context.
27func (c Context) Dict(key string, dict *Event) Context {
28	dict.buf = enc.AppendEndMarker(dict.buf)
29	c.l.context = append(enc.AppendKey(c.l.context, key), dict.buf...)
30	putEvent(dict)
31	return c
32}
33
34// Array adds the field key with an array to the event context.
35// Use zerolog.Arr() to create the array or pass a type that
36// implement the LogArrayMarshaler interface.
37func (c Context) Array(key string, arr LogArrayMarshaler) Context {
38	c.l.context = enc.AppendKey(c.l.context, key)
39	if arr, ok := arr.(*Array); ok {
40		c.l.context = arr.write(c.l.context)
41		return c
42	}
43	var a *Array
44	if aa, ok := arr.(*Array); ok {
45		a = aa
46	} else {
47		a = Arr()
48		arr.MarshalZerologArray(a)
49	}
50	c.l.context = a.write(c.l.context)
51	return c
52}
53
54// Object marshals an object that implement the LogObjectMarshaler interface.
55func (c Context) Object(key string, obj LogObjectMarshaler) Context {
56	e := newEvent(levelWriterAdapter{ioutil.Discard}, 0)
57	e.Object(key, obj)
58	c.l.context = enc.AppendObjectData(c.l.context, e.buf)
59	putEvent(e)
60	return c
61}
62
63// EmbedObject marshals and Embeds an object that implement the LogObjectMarshaler interface.
64func (c Context) EmbedObject(obj LogObjectMarshaler) Context {
65	e := newEvent(levelWriterAdapter{ioutil.Discard}, 0)
66	e.EmbedObject(obj)
67	c.l.context = enc.AppendObjectData(c.l.context, e.buf)
68	putEvent(e)
69	return c
70}
71
72// Str adds the field key with val as a string to the logger context.
73func (c Context) Str(key, val string) Context {
74	c.l.context = enc.AppendString(enc.AppendKey(c.l.context, key), val)
75	return c
76}
77
78// Strs adds the field key with val as a string to the logger context.
79func (c Context) Strs(key string, vals []string) Context {
80	c.l.context = enc.AppendStrings(enc.AppendKey(c.l.context, key), vals)
81	return c
82}
83
84// Bytes adds the field key with val as a []byte to the logger context.
85func (c Context) Bytes(key string, val []byte) Context {
86	c.l.context = enc.AppendBytes(enc.AppendKey(c.l.context, key), val)
87	return c
88}
89
90// Hex adds the field key with val as a hex string to the logger context.
91func (c Context) Hex(key string, val []byte) Context {
92	c.l.context = enc.AppendHex(enc.AppendKey(c.l.context, key), val)
93	return c
94}
95
96// RawJSON adds already encoded JSON to context.
97//
98// No sanity check is performed on b; it must not contain carriage returns and
99// be valid JSON.
100func (c Context) RawJSON(key string, b []byte) Context {
101	c.l.context = appendJSON(enc.AppendKey(c.l.context, key), b)
102	return c
103}
104
105// AnErr adds the field key with serialized err to the logger context.
106func (c Context) AnErr(key string, err error) Context {
107	switch m := ErrorMarshalFunc(err).(type) {
108	case nil:
109		return c
110	case LogObjectMarshaler:
111		return c.Object(key, m)
112	case error:
113		if m == nil || isNilValue(m) {
114			return c
115		} else {
116			return c.Str(key, m.Error())
117		}
118	case string:
119		return c.Str(key, m)
120	default:
121		return c.Interface(key, m)
122	}
123}
124
125// Errs adds the field key with errs as an array of serialized errors to the
126// logger context.
127func (c Context) Errs(key string, errs []error) Context {
128	arr := Arr()
129	for _, err := range errs {
130		switch m := ErrorMarshalFunc(err).(type) {
131		case LogObjectMarshaler:
132			arr = arr.Object(m)
133		case error:
134			if m == nil || isNilValue(m) {
135				arr = arr.Interface(nil)
136			} else {
137				arr = arr.Str(m.Error())
138			}
139		case string:
140			arr = arr.Str(m)
141		default:
142			arr = arr.Interface(m)
143		}
144	}
145
146	return c.Array(key, arr)
147}
148
149// Err adds the field "error" with serialized err to the logger context.
150func (c Context) Err(err error) Context {
151	return c.AnErr(ErrorFieldName, err)
152}
153
154// Bool adds the field key with val as a bool to the logger context.
155func (c Context) Bool(key string, b bool) Context {
156	c.l.context = enc.AppendBool(enc.AppendKey(c.l.context, key), b)
157	return c
158}
159
160// Bools adds the field key with val as a []bool to the logger context.
161func (c Context) Bools(key string, b []bool) Context {
162	c.l.context = enc.AppendBools(enc.AppendKey(c.l.context, key), b)
163	return c
164}
165
166// Int adds the field key with i as a int to the logger context.
167func (c Context) Int(key string, i int) Context {
168	c.l.context = enc.AppendInt(enc.AppendKey(c.l.context, key), i)
169	return c
170}
171
172// Ints adds the field key with i as a []int to the logger context.
173func (c Context) Ints(key string, i []int) Context {
174	c.l.context = enc.AppendInts(enc.AppendKey(c.l.context, key), i)
175	return c
176}
177
178// Int8 adds the field key with i as a int8 to the logger context.
179func (c Context) Int8(key string, i int8) Context {
180	c.l.context = enc.AppendInt8(enc.AppendKey(c.l.context, key), i)
181	return c
182}
183
184// Ints8 adds the field key with i as a []int8 to the logger context.
185func (c Context) Ints8(key string, i []int8) Context {
186	c.l.context = enc.AppendInts8(enc.AppendKey(c.l.context, key), i)
187	return c
188}
189
190// Int16 adds the field key with i as a int16 to the logger context.
191func (c Context) Int16(key string, i int16) Context {
192	c.l.context = enc.AppendInt16(enc.AppendKey(c.l.context, key), i)
193	return c
194}
195
196// Ints16 adds the field key with i as a []int16 to the logger context.
197func (c Context) Ints16(key string, i []int16) Context {
198	c.l.context = enc.AppendInts16(enc.AppendKey(c.l.context, key), i)
199	return c
200}
201
202// Int32 adds the field key with i as a int32 to the logger context.
203func (c Context) Int32(key string, i int32) Context {
204	c.l.context = enc.AppendInt32(enc.AppendKey(c.l.context, key), i)
205	return c
206}
207
208// Ints32 adds the field key with i as a []int32 to the logger context.
209func (c Context) Ints32(key string, i []int32) Context {
210	c.l.context = enc.AppendInts32(enc.AppendKey(c.l.context, key), i)
211	return c
212}
213
214// Int64 adds the field key with i as a int64 to the logger context.
215func (c Context) Int64(key string, i int64) Context {
216	c.l.context = enc.AppendInt64(enc.AppendKey(c.l.context, key), i)
217	return c
218}
219
220// Ints64 adds the field key with i as a []int64 to the logger context.
221func (c Context) Ints64(key string, i []int64) Context {
222	c.l.context = enc.AppendInts64(enc.AppendKey(c.l.context, key), i)
223	return c
224}
225
226// Uint adds the field key with i as a uint to the logger context.
227func (c Context) Uint(key string, i uint) Context {
228	c.l.context = enc.AppendUint(enc.AppendKey(c.l.context, key), i)
229	return c
230}
231
232// Uints adds the field key with i as a []uint to the logger context.
233func (c Context) Uints(key string, i []uint) Context {
234	c.l.context = enc.AppendUints(enc.AppendKey(c.l.context, key), i)
235	return c
236}
237
238// Uint8 adds the field key with i as a uint8 to the logger context.
239func (c Context) Uint8(key string, i uint8) Context {
240	c.l.context = enc.AppendUint8(enc.AppendKey(c.l.context, key), i)
241	return c
242}
243
244// Uints8 adds the field key with i as a []uint8 to the logger context.
245func (c Context) Uints8(key string, i []uint8) Context {
246	c.l.context = enc.AppendUints8(enc.AppendKey(c.l.context, key), i)
247	return c
248}
249
250// Uint16 adds the field key with i as a uint16 to the logger context.
251func (c Context) Uint16(key string, i uint16) Context {
252	c.l.context = enc.AppendUint16(enc.AppendKey(c.l.context, key), i)
253	return c
254}
255
256// Uints16 adds the field key with i as a []uint16 to the logger context.
257func (c Context) Uints16(key string, i []uint16) Context {
258	c.l.context = enc.AppendUints16(enc.AppendKey(c.l.context, key), i)
259	return c
260}
261
262// Uint32 adds the field key with i as a uint32 to the logger context.
263func (c Context) Uint32(key string, i uint32) Context {
264	c.l.context = enc.AppendUint32(enc.AppendKey(c.l.context, key), i)
265	return c
266}
267
268// Uints32 adds the field key with i as a []uint32 to the logger context.
269func (c Context) Uints32(key string, i []uint32) Context {
270	c.l.context = enc.AppendUints32(enc.AppendKey(c.l.context, key), i)
271	return c
272}
273
274// Uint64 adds the field key with i as a uint64 to the logger context.
275func (c Context) Uint64(key string, i uint64) Context {
276	c.l.context = enc.AppendUint64(enc.AppendKey(c.l.context, key), i)
277	return c
278}
279
280// Uints64 adds the field key with i as a []uint64 to the logger context.
281func (c Context) Uints64(key string, i []uint64) Context {
282	c.l.context = enc.AppendUints64(enc.AppendKey(c.l.context, key), i)
283	return c
284}
285
286// Float32 adds the field key with f as a float32 to the logger context.
287func (c Context) Float32(key string, f float32) Context {
288	c.l.context = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f)
289	return c
290}
291
292// Floats32 adds the field key with f as a []float32 to the logger context.
293func (c Context) Floats32(key string, f []float32) Context {
294	c.l.context = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f)
295	return c
296}
297
298// Float64 adds the field key with f as a float64 to the logger context.
299func (c Context) Float64(key string, f float64) Context {
300	c.l.context = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f)
301	return c
302}
303
304// Floats64 adds the field key with f as a []float64 to the logger context.
305func (c Context) Floats64(key string, f []float64) Context {
306	c.l.context = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f)
307	return c
308}
309
310type timestampHook struct{}
311
312func (ts timestampHook) Run(e *Event, level Level, msg string) {
313	e.Timestamp()
314}
315
316var th = timestampHook{}
317
318// Timestamp adds the current local time as UNIX timestamp to the logger context with the "time" key.
319// To customize the key name, change zerolog.TimestampFieldName.
320//
321// NOTE: It won't dedupe the "time" key if the *Context has one already.
322func (c Context) Timestamp() Context {
323	c.l = c.l.Hook(th)
324	return c
325}
326
327// Time adds the field key with t formated as string using zerolog.TimeFieldFormat.
328func (c Context) Time(key string, t time.Time) Context {
329	c.l.context = enc.AppendTime(enc.AppendKey(c.l.context, key), t, TimeFieldFormat)
330	return c
331}
332
333// Times adds the field key with t formated as string using zerolog.TimeFieldFormat.
334func (c Context) Times(key string, t []time.Time) Context {
335	c.l.context = enc.AppendTimes(enc.AppendKey(c.l.context, key), t, TimeFieldFormat)
336	return c
337}
338
339// Dur adds the fields key with d divided by unit and stored as a float.
340func (c Context) Dur(key string, d time.Duration) Context {
341	c.l.context = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger)
342	return c
343}
344
345// Durs adds the fields key with d divided by unit and stored as a float.
346func (c Context) Durs(key string, d []time.Duration) Context {
347	c.l.context = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger)
348	return c
349}
350
351// Interface adds the field key with obj marshaled using reflection.
352func (c Context) Interface(key string, i interface{}) Context {
353	c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), i)
354	return c
355}
356
357type callerHook struct {
358	callerSkipFrameCount int
359}
360
361func newCallerHook(skipFrameCount int) callerHook {
362	return callerHook{callerSkipFrameCount: skipFrameCount}
363}
364
365func (ch callerHook) Run(e *Event, level Level, msg string) {
366	switch ch.callerSkipFrameCount {
367	case useGlobalSkipFrameCount:
368		// Extra frames to skip (added by hook infra).
369		e.caller(CallerSkipFrameCount + contextCallerSkipFrameCount)
370	default:
371		// Extra frames to skip (added by hook infra).
372		e.caller(ch.callerSkipFrameCount + contextCallerSkipFrameCount)
373	}
374}
375
376// useGlobalSkipFrameCount acts as a flag to informat callerHook.Run
377// to use the global CallerSkipFrameCount.
378const useGlobalSkipFrameCount = math.MinInt32
379
380// ch is the default caller hook using the global CallerSkipFrameCount.
381var ch = newCallerHook(useGlobalSkipFrameCount)
382
383// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
384func (c Context) Caller() Context {
385	c.l = c.l.Hook(ch)
386	return c
387}
388
389// CallerWithSkipFrameCount adds the file:line of the caller with the zerolog.CallerFieldName key.
390// The specified skipFrameCount int will override the global CallerSkipFrameCount for this context's respective logger.
391// If set to -1 the global CallerSkipFrameCount will be used.
392func (c Context) CallerWithSkipFrameCount(skipFrameCount int) Context {
393	c.l = c.l.Hook(newCallerHook(skipFrameCount))
394	return c
395}
396
397type stackTraceHook struct{}
398
399func (sh stackTraceHook) Run(e *Event, level Level, msg string) {
400	e.Stack()
401}
402
403var sh = stackTraceHook{}
404
405// Stack enables stack trace printing for the error passed to Err().
406func (c Context) Stack() Context {
407	c.l = c.l.Hook(sh)
408	return c
409}
410
411// IPAddr adds IPv4 or IPv6 Address to the context
412func (c Context) IPAddr(key string, ip net.IP) Context {
413	c.l.context = enc.AppendIPAddr(enc.AppendKey(c.l.context, key), ip)
414	return c
415}
416
417// IPPrefix adds IPv4 or IPv6 Prefix (address and mask) to the context
418func (c Context) IPPrefix(key string, pfx net.IPNet) Context {
419	c.l.context = enc.AppendIPPrefix(enc.AppendKey(c.l.context, key), pfx)
420	return c
421}
422
423// MACAddr adds MAC address to the context
424func (c Context) MACAddr(key string, ha net.HardwareAddr) Context {
425	c.l.context = enc.AppendMACAddr(enc.AppendKey(c.l.context, key), ha)
426	return c
427}
428