blob: 3a81ec628a7f140aae532a172ac49355d28abee1 [file] [log] [blame]
Serge Bazanski5faa2fc2020-09-07 14:09:30 +02001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package logtree
18
19import (
20 "fmt"
Serge Bazanskif68153c2020-10-26 13:54:37 +010021 "io"
Serge Bazanski5faa2fc2020-09-07 14:09:30 +020022 "runtime"
23 "strings"
24 "time"
Serge Bazanskif68153c2020-10-26 13:54:37 +010025
26 "git.monogon.dev/source/nexantic.git/core/pkg/logbuffer"
Serge Bazanski5faa2fc2020-09-07 14:09:30 +020027)
28
29// LeveledFor returns a LeveledLogger publishing interface for a given DN. An error may be returned if the DN is
30// malformed.
31func (l *LogTree) LeveledFor(dn DN) (LeveledLogger, error) {
32 return l.nodeByDN(dn)
33}
34
Serge Bazanskif68153c2020-10-26 13:54:37 +010035func (l *LogTree) RawFor(dn DN) (io.Writer, error) {
36 node, err := l.nodeByDN(dn)
37 if err != nil {
38 return nil, fmt.Errorf("could not retrieve raw logger: %w", err)
39 }
40 return node.rawLineBuffer, nil
41}
42
Serge Bazanski5faa2fc2020-09-07 14:09:30 +020043// MustLeveledFor returns a LeveledLogger publishing interface for a given DN, or panics if the given DN is invalid.
44func (l *LogTree) MustLeveledFor(dn DN) LeveledLogger {
45 leveled, err := l.LeveledFor(dn)
46 if err != nil {
47 panic(fmt.Errorf("LeveledFor returned: %w", err))
48 }
49 return leveled
50}
51
Serge Bazanskif68153c2020-10-26 13:54:37 +010052func (l *LogTree) MustRawFor(dn DN) io.Writer {
53 raw, err := l.RawFor(dn)
54 if err != nil {
55 panic(fmt.Errorf("RawFor returned: %w", err))
56 }
57 return raw
58}
59
Serge Bazanski5faa2fc2020-09-07 14:09:30 +020060// SetVerbosity sets the verbosity for a given DN (non-recursively, ie. for that DN only, not its children).
61func (l *LogTree) SetVerbosity(dn DN, level VerbosityLevel) error {
62 node, err := l.nodeByDN(dn)
63 if err != nil {
64 return err
65 }
66 node.verbosity = level
67 return nil
68}
69
Serge Bazanskif68153c2020-10-26 13:54:37 +010070// logRaw is called by this node's LineBuffer any time a raw log line is completed. It will create a new entry, append
71// it to the journal, and notify all pertinent subscribers.
72func (n *node) logRaw(line *logbuffer.Line) {
73 e := &entry{
74 origin: n.dn,
75 raw: line,
76 }
77 n.tree.journal.append(e)
78 n.tree.journal.notify(e)
79}
80
81// log builds a LeveledPayload and entry for a given message, including all related metadata. It will create a new
82// entry append it to the journal, and notify all pertinent subscribers.
83func (n *node) logLeveled(depth int, severity Severity, msg string) {
Serge Bazanski5faa2fc2020-09-07 14:09:30 +020084 _, file, line, ok := runtime.Caller(2 + depth)
85 if !ok {
86 file = "???"
87 line = 1
88 } else {
89 slash := strings.LastIndex(file, "/")
90 if slash >= 0 {
91 file = file[slash+1:]
92 }
93 }
Serge Bazanski1bfa0c22020-10-14 16:45:07 +020094 p := &LeveledPayload{
Serge Bazanski5faa2fc2020-09-07 14:09:30 +020095 timestamp: time.Now(),
96 severity: severity,
97 message: msg,
98 file: file,
99 line: line,
100 }
101 e := &entry{
102 origin: n.dn,
Serge Bazanski1bfa0c22020-10-14 16:45:07 +0200103 leveled: p,
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200104 }
105 n.tree.journal.append(e)
106 n.tree.journal.notify(e)
107}
108
109// Info implements the LeveledLogger interface.
110func (n *node) Info(args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100111 n.logLeveled(0, INFO, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200112}
113
114// Infof implements the LeveledLogger interface.
115func (n *node) Infof(format string, args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100116 n.logLeveled(0, INFO, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200117}
118
119// Warning implements the LeveledLogger interface.
120func (n *node) Warning(args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100121 n.logLeveled(0, WARNING, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200122}
123
124// Warningf implements the LeveledLogger interface.
125func (n *node) Warningf(format string, args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100126 n.logLeveled(0, WARNING, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200127}
128
129// Error implements the LeveledLogger interface.
130func (n *node) Error(args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100131 n.logLeveled(0, ERROR, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200132}
133
134// Errorf implements the LeveledLogger interface.
135func (n *node) Errorf(format string, args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100136 n.logLeveled(0, ERROR, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200137}
138
139// Fatal implements the LeveledLogger interface.
140func (n *node) Fatal(args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100141 n.logLeveled(0, FATAL, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200142}
143
144// Fatalf implements the LeveledLogger interface.
145func (n *node) Fatalf(format string, args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100146 n.logLeveled(0, FATAL, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200147}
148
149// V implements the LeveledLogger interface.
150func (n *node) V(v VerbosityLevel) VerboseLeveledLogger {
151 return &verbose{
152 node: n,
153 enabled: n.verbosity >= v,
154 }
155}
156
157// verbose implements the VerboseLeveledLogger interface. It is a thin wrapper around node, with an 'enabled' bool. This
158// means that V(n)-returned VerboseLeveledLoggers must be short lived, as a changed in verbosity will not affect all
159// already existing VerboseLeveledLoggers.
160type verbose struct {
161 node *node
162 enabled bool
163}
164
165func (v *verbose) Enabled() bool {
166 return v.enabled
167}
168
169func (v *verbose) Info(args ...interface{}) {
170 if !v.enabled {
171 return
172 }
Serge Bazanskif68153c2020-10-26 13:54:37 +0100173 v.node.logLeveled(0, INFO, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200174}
175
176func (v *verbose) Infof(format string, args ...interface{}) {
177 if !v.enabled {
178 return
179 }
Serge Bazanskif68153c2020-10-26 13:54:37 +0100180 v.node.logLeveled(0, INFO, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200181}