forked from asynkron/protoactor-go
-
Notifications
You must be signed in to change notification settings - Fork 12
/
field.go
220 lines (189 loc) · 6.12 KB
/
field.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/****************************************************
Copyright 2018 The ont-eventbus Authors
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.
*****************************************************/
/***************************************************
Copyright 2016 https://github.com/AsynkronIT/protoactor-go
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 (
"fmt"
"math"
"reflect"
"runtime"
"strings"
"time"
)
type fieldType int
const (
unknownType fieldType = iota
boolType
floatType
intType
int64Type
durationType
uintType
uint64Type
stringType
stringerType
errorType
objectType
typeOfType
skipType
)
type Field struct {
key string
fieldType fieldType
val int64
str string
obj interface{}
}
// Bool constructs a Field with the given key and value.
func Bool(key string, val bool) Field {
var ival int64
if val {
ival = 1
}
return Field{key: key, fieldType: boolType, val: ival}
}
// Float64 constructs a Field with the given key and value.
func Float64(key string, val float64) Field {
return Field{key: key, fieldType: floatType, val: int64(math.Float64bits(val))}
}
// Int constructs a Field with the given key and value. Marshaling ints is lazy.
func Int(key string, val int) Field {
return Field{key: key, fieldType: intType, val: int64(val)}
}
// Int64 constructs a Field with the given key and value.
func Int64(key string, val int64) Field {
return Field{key: key, fieldType: int64Type, val: val}
}
// Uint constructs a Field with the given key and value.
func Uint(key string, val uint) Field {
return Field{key: key, fieldType: uintType, val: int64(val)}
}
// Uint64 constructs a Field with the given key and value.
func Uint64(key string, val uint64) Field {
return Field{key: key, fieldType: uint64Type, val: int64(val)}
}
// String constructs a Field with the given key and value.
func String(key string, val string) Field {
return Field{key: key, fieldType: stringType, str: val}
}
// Stringer constructs a Field with the given key and the output of the value's
// String method. The String is not evaluated until encoding.
func Stringer(key string, val fmt.Stringer) Field {
if val == nil {
return Field{key: key, fieldType: objectType, obj: val}
}
return Field{key: key, fieldType: stringerType, obj: val}
}
// Time constructs a Field with the given key and value. It represents a
// time.Time as a floating-point number of seconds since the Unix epoch.
func Time(key string, val time.Time) Field {
return Float64(key, float64(val.UnixNano())/float64(time.Second))
}
// Error constructs a Field that lazily stores err.Error() under the key
// "error". If passed a nil error, the field is skipped.
func Error(err error) Field {
if err == nil {
return Field{fieldType: skipType}
}
return Field{key: "error", fieldType: errorType, obj: err}
}
// Stack constructs a Field that stores a stacktrace under the key "stacktrace".
//
// This is eager and therefore an expensive operation.
func Stack() Field {
var name, file string
var line int
var pc [16]uintptr
n := runtime.Callers(4, pc[:])
for _, pc := range pc[:n] {
fn := runtime.FuncForPC(pc)
if fn == nil {
continue
}
file, line = fn.FileLine(pc)
name = fn.Name()
if !strings.HasPrefix(name, "runtime.") {
break
}
}
var str string
switch {
case name != "":
str = fmt.Sprintf("%v:%v", name, line)
case file != "":
str = fmt.Sprintf("%v:%v", file, line)
default:
str = fmt.Sprintf("pc:%x", pc)
}
return String("stacktrace", str)
}
// Duration constructs a Field with the given key and value.
func Duration(key string, val time.Duration) Field {
return Field{key: key, fieldType: durationType, val: int64(val)}
}
// Object constructs a field with the given key and an arbitrary object.
func Object(key string, val interface{}) Field {
return Field{key: key, fieldType: objectType, obj: val}
}
// TypeOf constructs a field with the given key and an arbitrary object that will log the type information lazily.
func TypeOf(key string, val interface{}) Field {
return Field{key: key, fieldType: typeOfType, obj: val}
}
// Message constructs a field to store the message under the key message
func Message(val interface{}) Field {
return Field{key: "message", fieldType: objectType, obj: val}
}
// Encode encodes a field to a type safe val via the encoder.
func (f Field) Encode(enc Encoder) {
switch f.fieldType {
case boolType:
enc.EncodeBool(f.key, f.val == 1)
case floatType:
enc.EncodeFloat64(f.key, math.Float64frombits(uint64(f.val)))
case intType:
enc.EncodeInt(f.key, int(f.val))
case int64Type:
enc.EncodeInt64(f.key, f.val)
case durationType:
enc.EncodeDuration(f.key, time.Duration(f.val))
case uintType:
enc.EncodeUint(f.key, uint(f.val))
case uint64Type:
enc.EncodeUint64(f.key, uint64(f.val))
case stringType:
enc.EncodeString(f.key, f.str)
case stringerType:
enc.EncodeString(f.key, f.obj.(fmt.Stringer).String())
case errorType:
enc.EncodeString(f.key, f.obj.(error).Error())
case objectType:
enc.EncodeObject(f.key, f.obj)
case typeOfType:
enc.EncodeType(f.key, reflect.TypeOf(f.obj))
case skipType:
break
default:
panic(fmt.Sprintf("unknown field type found: %v", f))
}
}