File tree 2 files changed +48
-3
lines changed
2 files changed +48
-3
lines changed Original file line number Diff line number Diff line change @@ -12,6 +12,7 @@ import (
12
12
"reflect"
13
13
"strconv"
14
14
"strings"
15
+ "syscall"
15
16
"time"
16
17
"unicode"
17
18
@@ -224,9 +225,25 @@ func isTTY(w io.Writer) bool {
224
225
if w == forceColorWriter {
225
226
return true
226
227
}
227
- f , ok := w .(interface {
228
- Fd () uintptr
229
- })
228
+ // SyscallConn is safe during file close.
229
+ if sc , ok := w .(interface {
230
+ SyscallConn () (syscall.RawConn , error )
231
+ }); ok {
232
+ conn , err := sc .SyscallConn ()
233
+ if err != nil {
234
+ return false
235
+ }
236
+ var isTerm bool
237
+ err = conn .Control (func (fd uintptr ) {
238
+ isTerm = term .IsTerminal (int (fd ))
239
+ })
240
+ if err != nil {
241
+ return false
242
+ }
243
+ return isTerm
244
+ }
245
+ // Fallback to unsafe Fd.
246
+ f , ok := w .(interface { Fd () uintptr })
230
247
return ok && term .IsTerminal (int (f .Fd ()))
231
248
}
232
249
Original file line number Diff line number Diff line change @@ -178,6 +178,34 @@ func TestEntry(t *testing.T) {
178
178
assert .Equal (t , "entry matches" , string (wantByt ), gotBuf .String ())
179
179
})
180
180
}
181
+
182
+ t .Run ("isTTY during file close" , func (t * testing.T ) {
183
+ t .Parallel ()
184
+
185
+ tmpdir := t .TempDir ()
186
+ f , err := os .CreateTemp (tmpdir , "slog" )
187
+ if err != nil {
188
+ t .Fatal (err )
189
+ }
190
+ defer f .Close ()
191
+
192
+ done := make (chan struct {}, 2 )
193
+ go func () {
194
+ entryhuman .Fmt (new (bytes.Buffer ), f , slog.SinkEntry {
195
+ Level : slog .LevelCritical ,
196
+ Fields : slog .M (
197
+ slog .F ("hey" , "hi" ),
198
+ ),
199
+ })
200
+ done <- struct {}{}
201
+ }()
202
+ go func () {
203
+ _ = f .Close ()
204
+ done <- struct {}{}
205
+ }()
206
+ <- done
207
+ <- done
208
+ })
181
209
}
182
210
183
211
func BenchmarkFmt (b * testing.B ) {
You can’t perform that action at this time.
0 commit comments