Source file
src/go.uber.org/zap/stacktrace_ext_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package zap_test
22
23 import (
24 "bytes"
25 "encoding/json"
26 "os"
27 "os/exec"
28 "path/filepath"
29 "runtime"
30 "strings"
31 "testing"
32
33 "go.uber.org/zap"
34 "go.uber.org/zap/zapcore"
35
36 "github.com/stretchr/testify/assert"
37 "github.com/stretchr/testify/require"
38 )
39
40
41
42
43
44 var _zapPackages = []string{
45 "go.uber.org/zap.",
46 "go.uber.org/zap/zapcore.",
47 }
48
49 func TestStacktraceFiltersZapLog(t *testing.T) {
50 withLogger(t, func(logger *zap.Logger, out *bytes.Buffer) {
51 logger.Error("test log")
52 logger.Sugar().Error("sugar test log")
53
54 require.Contains(t, out.String(), "TestStacktraceFiltersZapLog", "Should not strip out non-zap import")
55 verifyNoZap(t, out.String())
56 })
57 }
58
59 func TestStacktraceFiltersZapMarshal(t *testing.T) {
60 withLogger(t, func(logger *zap.Logger, out *bytes.Buffer) {
61 marshal := func(enc zapcore.ObjectEncoder) error {
62 logger.Warn("marshal caused warn")
63 enc.AddString("f", "v")
64 return nil
65 }
66 logger.Error("test log", zap.Object("obj", zapcore.ObjectMarshalerFunc(marshal)))
67
68 logs := out.String()
69
70
71 const marshalFnPrefix = "TestStacktraceFiltersZapMarshal."
72 require.Contains(t, logs, marshalFnPrefix, "Should not strip out marshal call")
73
74
75 marshalIndex := strings.Index(logs, marshalFnPrefix)
76 verifyNoZap(t, logs[:marshalIndex])
77
78
79
80 for _, fnPrefix := range _zapPackages {
81 require.Contains(t, logs[marshalIndex:], fnPrefix, "Missing zap caller stack for Marshal")
82 }
83 })
84 }
85
86 func TestStacktraceFiltersVendorZap(t *testing.T) {
87
88
89 deps := downloadDependencies(t)
90
91
92
93
94 withGoPath(t, func(goPath string) {
95 zapDir, err := os.Getwd()
96 require.NoError(t, err, "Failed to get current directory")
97
98 testDir := filepath.Join(goPath, "src/go.uber.org/zap_test/")
99 vendorDir := filepath.Join(testDir, "vendor")
100 require.NoError(t, os.MkdirAll(testDir, 0o777), "Failed to create source director")
101
102 curFile := getSelfFilename(t)
103 setupSymlink(t, curFile, filepath.Join(testDir, curFile))
104
105
106 setupSymlink(t, zapDir, filepath.Join(vendorDir, "go.uber.org/zap"))
107 for _, dep := range deps {
108 setupSymlink(t, dep.Dir, filepath.Join(vendorDir, dep.ImportPath))
109 }
110
111
112
113 cmd := exec.Command("go", "test", "-v", "-run", "TestStacktraceFiltersZap")
114 cmd.Dir = testDir
115 cmd.Env = append(os.Environ(), "GO111MODULE=off")
116 out, err := cmd.CombinedOutput()
117 require.NoError(t, err, "Failed to run test in vendor directory, output: %s", out)
118 assert.Contains(t, string(out), "PASS")
119 })
120 }
121
122 func TestStacktraceWithoutCallerSkip(t *testing.T) {
123 withLogger(t, func(logger *zap.Logger, out *bytes.Buffer) {
124 func() {
125 logger.Error("test log")
126 }()
127
128 require.Contains(t, out.String(), "TestStacktraceWithoutCallerSkip.", "Should not skip too much")
129 verifyNoZap(t, out.String())
130 })
131 }
132
133 func TestStacktraceWithCallerSkip(t *testing.T) {
134 withLogger(t, func(logger *zap.Logger, out *bytes.Buffer) {
135 logger = logger.WithOptions(zap.AddCallerSkip(2))
136 func() {
137 logger.Error("test log")
138 }()
139
140 require.NotContains(t, out.String(), "TestStacktraceWithCallerSkip.", "Should skip as requested by caller skip")
141 require.Contains(t, out.String(), "TestStacktraceWithCallerSkip", "Should not skip too much")
142 verifyNoZap(t, out.String())
143 })
144 }
145
146
147
148 func withLogger(t *testing.T, fn func(logger *zap.Logger, out *bytes.Buffer)) {
149 buf := &bytes.Buffer{}
150 encoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
151 core := zapcore.NewCore(encoder, zapcore.AddSync(buf), zapcore.DebugLevel)
152 logger := zap.New(core, zap.AddStacktrace(zap.DebugLevel))
153 fn(logger, buf)
154 }
155
156 func verifyNoZap(t *testing.T, logs string) {
157 for _, fnPrefix := range _zapPackages {
158 require.NotContains(t, logs, fnPrefix, "Should not strip out marshal call")
159 }
160 }
161
162 func withGoPath(t *testing.T, f func(goPath string)) {
163 goPath := filepath.Join(t.TempDir(), "gopath")
164 t.Setenv("GOPATH", goPath)
165
166 f(goPath)
167 }
168
169 func getSelfFilename(t *testing.T) string {
170 _, file, _, ok := runtime.Caller(0)
171 require.True(t, ok, "Failed to get caller information to identify local file")
172
173 return filepath.Base(file)
174 }
175
176 func setupSymlink(t *testing.T, src, dst string) {
177
178 require.NoError(t, os.MkdirAll(filepath.Dir(dst), 0o777))
179
180
181
182 srcAbs, err := filepath.Abs(src)
183 require.NoError(t, err, "Failed to get absolute path")
184
185 require.NoError(t, os.Symlink(srcAbs, dst), "Failed to set up symlink")
186 }
187
188 type dependency struct {
189 ImportPath string `json:"Path"`
190 Dir string `json:"Dir"`
191 }
192
193
194
195 func downloadDependencies(t *testing.T) []dependency {
196 cmd := exec.Command("go", "mod", "download", "-json")
197
198 stdout, err := cmd.Output()
199 require.NoError(t, err, "Failed to run 'go mod download'")
200
201 var deps []dependency
202 dec := json.NewDecoder(bytes.NewBuffer(stdout))
203 for dec.More() {
204 var d dependency
205 require.NoError(t, dec.Decode(&d), "Failed to decode dependency")
206 deps = append(deps, d)
207 }
208
209 return deps
210 }
211
View as plain text