File: logger.go

package info (click to toggle)
golang-github-newrelic-go-agent 3.15.2-9
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 8,356 kB
  • sloc: sh: 65; makefile: 6
file content (102 lines) | stat: -rw-r--r-- 2,746 bytes parent folder | download
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
// Copyright 2020 New Relic Corporation. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package logger

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
)

// Logger matches newrelic.Logger to allow implementations to be passed to
// internal packages.
type Logger interface {
	Error(msg string, context map[string]interface{})
	Warn(msg string, context map[string]interface{})
	Info(msg string, context map[string]interface{})
	Debug(msg string, context map[string]interface{})
	DebugEnabled() bool
}

// ShimLogger implements Logger and does nothing.
type ShimLogger struct {
	// IsDebugEnabled is useful as it allows DebugEnabled code paths to be
	// tested.
	IsDebugEnabled bool
}

// Error allows ShimLogger to implement Logger.
func (s ShimLogger) Error(string, map[string]interface{}) {}

// Warn allows ShimLogger to implement Logger.
func (s ShimLogger) Warn(string, map[string]interface{}) {}

// Info allows ShimLogger to implement Logger.
func (s ShimLogger) Info(string, map[string]interface{}) {}

// Debug allows ShimLogger to implement Logger.
func (s ShimLogger) Debug(string, map[string]interface{}) {}

// DebugEnabled allows ShimLogger to implement Logger.
func (s ShimLogger) DebugEnabled() bool { return s.IsDebugEnabled }

type logFile struct {
	l       *log.Logger
	doDebug bool
}

// New creates a basic Logger.
func New(w io.Writer, doDebug bool) Logger {
	return &logFile{
		l:       log.New(w, logPid, logFlags),
		doDebug: doDebug,
	}
}

const logFlags = log.Ldate | log.Ltime | log.Lmicroseconds

var (
	logPid = fmt.Sprintf("(%d) ", os.Getpid())
)

func (f *logFile) fire(level, msg string, ctx map[string]interface{}) {
	js, err := json.Marshal(struct {
		Level   string                 `json:"level"`
		Event   string                 `json:"msg"`
		Context map[string]interface{} `json:"context"`
	}{
		level,
		msg,
		ctx,
	})
	if err == nil {
		// scrub license keys from any portion of the log message
		re := regexp.MustCompile(`license_key=[a-fA-F0-9.]+`)
		sanitized := re.ReplaceAllLiteralString(string(js), "license_key=[redacted]")
		f.l.Print(sanitized)
	} else {
		f.l.Printf("unable to marshal log entry")
		// error value removed from message to avoid possibility of sensitive
		// content being leaked that way
	}
}

func (f *logFile) Error(msg string, ctx map[string]interface{}) {
	f.fire("error", msg, ctx)
}
func (f *logFile) Warn(msg string, ctx map[string]interface{}) {
	f.fire("warn", msg, ctx)
}
func (f *logFile) Info(msg string, ctx map[string]interface{}) {
	f.fire("info", msg, ctx)
}
func (f *logFile) Debug(msg string, ctx map[string]interface{}) {
	if f.doDebug {
		f.fire("debug", msg, ctx)
	}
}
func (f *logFile) DebugEnabled() bool { return f.doDebug }