-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathlogger_identity.go
122 lines (107 loc) · 3.64 KB
/
logger_identity.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
package log
import (
"fmt"
"github.com/dyweb/gommon/util/hashutil"
"github.com/dyweb/gommon/util/runtimeutil"
)
// LoggerType can be used for filtering loggers, it is set when creating logger
type LoggerType uint8
const (
UnknownLogger LoggerType = iota
// PackageLogger is normally singleton in entire package
// We used to have application and library logger but they are replaced by registry
PackageLogger
FunctionLogger
StructLogger
MethodLogger
)
var loggerTypeStrings = []string{
UnknownLogger: "unk",
PackageLogger: "pkg",
FunctionLogger: "func",
StructLogger: "struct",
MethodLogger: "method",
}
func (tpe LoggerType) String() string {
return loggerTypeStrings[tpe]
}
// Identity is set based on logger's initialization location,
// it is close to, but NOT exactly same as location of actual log.
// It can be used to inspect logger when traverse and print package hierarchy.
// NOTE: logger hierarchy is flat instead of tree after https://github.com/dyweb/gommon/issues/110
type Identity struct {
Package string
Function string
Struct string
File string
Line int
Type LoggerType
}
var UnknownIdentity = Identity{Package: "unk", Type: UnknownLogger}
const (
MagicStructLoggerFunctionName = "LoggerIdentity"
magicPackageLoggerFunctionName = "init"
// a hack for new init func name after 1.12
// See https://github.com/dyweb/gommon/issues/108
magicPackageLoggerFunctionNameGo112 = "init.ializers"
)
// newIdentityFromCaller get package, struct, func/method using runtime package to avoid user manually set identity
// of a logger to specific package, which is error prone and go out of sync quickly.
// TODO: document all the black magic here ...
// https://github.com/dyweb/gommon/issues/32
func newIdentityFromCaller(skip int) Identity {
frame := runtimeutil.GetCallerFrame(skip + 1)
var (
pkg string
function string
st string
)
tpe := UnknownLogger
// TODO: does it handle vendor correctly, and what about go mod ...
pkg, function = runtimeutil.SplitPackageFunc(frame.Function)
tpe = FunctionLogger
if function == magicPackageLoggerFunctionNameGo112 || function == magicPackageLoggerFunctionName {
// https://github.com/dyweb/gommon/issues/108 there are two names, init and init.ializers (after go1.12)
tpe = PackageLogger
} else if runtimeutil.IsMethod(function) {
// NOTE: we distinguish a struct logger and method logger using the magic name,
// which is normally the case as long as you are using the factory methods to create logger
// otherwise you have to manually update the type of logger
st, function = runtimeutil.SplitStructMethod(function)
tpe = MethodLogger
if function == MagicStructLoggerFunctionName {
tpe = StructLogger
}
}
return Identity{
Package: pkg,
Function: function,
Struct: st,
File: frame.File,
Line: frame.Line,
Type: tpe,
}
}
func (id *Identity) Hash() uint64 {
// assume no one create two logger in one line and no non ascii characters in file path
return hashutil.HashStringFnv64a(id.SourceLocation())
}
func (id *Identity) SourceLocation() string {
return fmt.Sprintf("%s:%d", id.File, id.Line)
}
func (id *Identity) String() string {
// TODO: add struct and func? or switch based on type
return fmt.Sprintf("%s logger %s:%d", id.Type, id.File, id.Line)
}
// TODO: this is used for print tree like structure ... it's hard to maintain exact parent and child logger due to cycle import
func (id *Identity) Diff(parent *Identity) string {
if parent == nil {
return id.Package
}
// TODO: might return full package
if id.Package != parent.Package {
return id.Package
}
// TODO: this may not be the desired behaviour
return id.File
}