-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcore.go
More file actions
178 lines (153 loc) · 5.96 KB
/
core.go
File metadata and controls
178 lines (153 loc) · 5.96 KB
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
// Copyright 2019 dfuse Platform Inc.
//
// 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 logging
import (
"bytes"
"fmt"
"net/http"
"os"
"strings"
"github.com/blendle/zapdriver"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var AutoStartServer = true
// Deprecated: You should use MustCreateLoggerWithServiceName
func MustCreateLogger(opts ...zap.Option) *zap.Logger {
return MustCreateLoggerWithServiceName("Unknown service", opts...)
}
// MustCreateLogger has the same behavior as `CreateLogger` function. However, it
// automatically panic if the logger was not created successfully.
func MustCreateLoggerWithServiceName(serviceName string, opts ...zap.Option) *zap.Logger {
return MustCreateLoggerWithLevel(serviceName, LevelFromEnvironment(), opts...)
}
// MustCreateLoggerWithLevel behaves exactly like `MustCreateLogger`, but you can pass the atomic level
// that should be used for the logger that will use this atomic level. By keeping a reference to it,
// later on, you will be able to change the level at runtime by calling `atomicLevel.SetLevel`
// on your reference and logger level will be changed.
func MustCreateLoggerWithLevel(serviceName string, atomicLevel zap.AtomicLevel, opts ...zap.Option) *zap.Logger {
logger, err := CreateLoggerWithLevel(serviceName, atomicLevel, opts...)
if err != nil {
panic(fmt.Errorf("unable to create logger (in production: %t): %s", IsProductionEnvironment(), err))
}
return logger
}
// CreateLogger can be used to create the correct zap logger based on the environment.
//
// First, if an environment variable `ZAP_PRETTY` pretty is present, a `zapdriver.NewProduction`
// is used but logging all levels (`Debug` level and more). Furthermore, this logger will
// print everything into the standard output of the process (opposed to standard error by
// default). If the env is set, it overrides everything. If the value of the `ZAP_PRETTY`
// environment variable is a valid Zap level (`debug`, `info`, `warn`, `error`), the logger
// level will be configured using the value. In all other cases, `debug` level is used as
// the default.
//
// Then, if in production, automatically a `zap.NewProduction()` is returned. The production
// environment is determined based on the presence of the `/.dockerenv` file.
//
// In all other cases, return a `zap.NewDevelopment()` logger.
func CreateLogger(serviceName string, opts ...zap.Option) (*zap.Logger, error) {
return CreateLoggerWithLevel(serviceName, LevelFromEnvironment(), opts...)
}
// CreateLoggerWithLevel behaves exactly like `CreateLogger`, but you can pass the atomic level
// that should be used for the logger that will use this atomic level. By keeping a reference to it,
// later on, you will be able to change the level at runtime by calling `atomicLevel.SetLevel`
// on your reference and logger level will be changed.
func CreateLoggerWithLevel(serviceName string, atomicLevel zap.AtomicLevel, opts ...zap.Option) (*zap.Logger, error) {
config := BasicLoggingConfig(serviceName, atomicLevel, opts...)
zlog, err := config.Build(opts...)
if err != nil {
return nil, err
}
if AutoStartServer {
go func() {
zlog.Info("starting atomic level switcher, port :1065")
if err := http.ListenAndServe(":1065", atomicLevel); err != nil {
zlog.Info("failed listening on :1065 to switch log level:", zap.Error(err))
}
}()
}
return zlog, nil
}
func LevelFromEnvironment() zap.AtomicLevel {
zapPrettyValue := os.Getenv("ZAP_PRETTY")
if zapPrettyValue != "" {
return zap.NewAtomicLevelAt(zapLevelFromString(zapPrettyValue))
}
if IsProductionEnvironment() {
return zap.NewAtomicLevelAt(zap.InfoLevel)
}
return zap.NewAtomicLevelAt(zap.DebugLevel)
}
func IsProductionEnvironment() bool {
// Inside Docker runtime, this file is populated
_, err := os.Stat("/.dockerenv")
if err == nil {
return true
}
// Inside container runtime the mounts can be inspected to see if we are running inside a container
if content, err := os.ReadFile("/proc/self/mounts"); err == nil {
// The containerd runtime mounts the container rootfs under `/var/lib/containerd`
if bytes.Contains(content, []byte("/var/lib/containerd")) {
return true
}
// The docker runtime mounts the container rootfs under `/var/lib/docker`
if bytes.Contains(content, []byte("/var/lib/docker")) {
return true
}
}
// Inside Kubernetes runtime, this env var is set
if os.Getenv("KUBERNETES_SERVICE_HOST") != "" {
return true
}
return false
}
// Deprecated: Will be removed in a future version, use `InstantiateLoggers` and configure it the way you want
// instead.
func BasicLoggingConfig(serviceName string, atomicLevel zap.AtomicLevel, opts ...zap.Option) *zap.Config {
var config zap.Config
if IsProductionEnvironment() || os.Getenv("ZAP_PRETTY") != "" {
config = zapdriver.NewProductionConfig()
opts = append(opts, zapdriver.WrapCore(
zapdriver.ReportAllErrors(true),
zapdriver.ServiceName(serviceName),
))
} else {
config = zap.NewDevelopmentConfig()
}
if os.Getenv("ZAP_PRETTY") != "" {
config.OutputPaths = []string{"stdout"}
config.ErrorOutputPaths = []string{"stdout"}
}
config.Level = atomicLevel
return &config
}
func zapLevelFromString(input string) zapcore.Level {
switch strings.ToLower(input) {
case "debug":
return zap.DebugLevel
case "info":
return zap.InfoLevel
case "warning", "warn":
return zap.WarnLevel
case "error", "err":
return zap.ErrorLevel
case "fatal":
return zap.FatalLevel
case "panic":
return zap.PanicLevel
default:
return zap.DebugLevel
}
}