github.com/netdata/go.d.plugin@v0.58.1/logger/logger.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package logger
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"log/slog"
     9  	"os"
    10  	"strconv"
    11  	"strings"
    12  	"sync/atomic"
    13  	"syscall"
    14  
    15  	"github.com/netdata/go.d.plugin/agent/executable"
    16  
    17  	"github.com/mattn/go-isatty"
    18  )
    19  
    20  var isTerm = isatty.IsTerminal(os.Stderr.Fd())
    21  
    22  var isJournal = isStderrConnectedToJournal()
    23  
    24  var pluginAttr = slog.String("plugin", executable.Name)
    25  
    26  func New() *Logger {
    27  	if isTerm {
    28  		// skip 2 slog pkg calls, 2 this pkg calls
    29  		return &Logger{sl: slog.New(withCallDepth(4, newTerminalHandler()))}
    30  	}
    31  	return &Logger{sl: slog.New(newTextHandler()).With(pluginAttr)}
    32  }
    33  
    34  type Logger struct {
    35  	muted atomic.Bool
    36  	sl    *slog.Logger
    37  }
    38  
    39  func (l *Logger) Error(a ...any)                   { l.log(slog.LevelError, fmt.Sprint(a...)) }
    40  func (l *Logger) Warning(a ...any)                 { l.log(slog.LevelWarn, fmt.Sprint(a...)) }
    41  func (l *Logger) Info(a ...any)                    { l.log(slog.LevelInfo, fmt.Sprint(a...)) }
    42  func (l *Logger) Debug(a ...any)                   { l.log(slog.LevelDebug, fmt.Sprint(a...)) }
    43  func (l *Logger) Errorf(format string, a ...any)   { l.log(slog.LevelError, fmt.Sprintf(format, a...)) }
    44  func (l *Logger) Warningf(format string, a ...any) { l.log(slog.LevelWarn, fmt.Sprintf(format, a...)) }
    45  func (l *Logger) Infof(format string, a ...any)    { l.log(slog.LevelInfo, fmt.Sprintf(format, a...)) }
    46  func (l *Logger) Debugf(format string, a ...any)   { l.log(slog.LevelDebug, fmt.Sprintf(format, a...)) }
    47  func (l *Logger) Mute()                            { l.mute(true) }
    48  func (l *Logger) Unmute()                          { l.mute(false) }
    49  
    50  func (l *Logger) With(args ...any) *Logger {
    51  	if l.isNil() {
    52  		return &Logger{sl: New().sl.With(args...)}
    53  	}
    54  
    55  	ll := &Logger{sl: l.sl.With(args...)}
    56  	ll.muted.Store(l.muted.Load())
    57  
    58  	return ll
    59  }
    60  
    61  func (l *Logger) log(level slog.Level, msg string) {
    62  	if l.isNil() {
    63  		nilLogger.sl.Log(context.Background(), level, msg)
    64  		return
    65  	}
    66  
    67  	if !l.muted.Load() {
    68  		l.sl.Log(context.Background(), level, msg)
    69  	}
    70  }
    71  
    72  func (l *Logger) mute(v bool) {
    73  	if l.isNil() || isTerm && Level.Enabled(slog.LevelDebug) {
    74  		return
    75  	}
    76  	l.muted.Store(v)
    77  }
    78  
    79  func (l *Logger) isNil() bool { return l == nil || l.sl == nil }
    80  
    81  var nilLogger = New()
    82  
    83  func isStderrConnectedToJournal() bool {
    84  	stream := os.Getenv("JOURNAL_STREAM")
    85  	if stream == "" {
    86  		return false
    87  	}
    88  
    89  	idx := strings.IndexByte(stream, ':')
    90  	if idx <= 0 {
    91  		return false
    92  	}
    93  
    94  	dev, ino := stream[:idx], stream[idx+1:]
    95  
    96  	var stat syscall.Stat_t
    97  	if err := syscall.Fstat(int(os.Stderr.Fd()), &stat); err != nil {
    98  		return false
    99  	}
   100  
   101  	return dev == strconv.Itoa(int(stat.Dev)) && ino == strconv.FormatUint(stat.Ino, 10)
   102  }