blob: c898012af0c99fb98107d142f5522a2ae68dadd6 [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 Bazanskib0272182020-11-02 18:39:44 +010094
Serge Bazanski1bfa0c22020-10-14 16:45:07 +020095 p := &LeveledPayload{
Serge Bazanski5faa2fc2020-09-07 14:09:30 +020096 timestamp: time.Now(),
97 severity: severity,
98 message: msg,
99 file: file,
100 line: line,
101 }
102 e := &entry{
103 origin: n.dn,
Serge Bazanski1bfa0c22020-10-14 16:45:07 +0200104 leveled: p,
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200105 }
106 n.tree.journal.append(e)
107 n.tree.journal.notify(e)
108}
109
110// Info implements the LeveledLogger interface.
111func (n *node) Info(args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100112 n.logLeveled(0, INFO, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200113}
114
115// Infof implements the LeveledLogger interface.
116func (n *node) Infof(format string, args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100117 n.logLeveled(0, INFO, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200118}
119
120// Warning implements the LeveledLogger interface.
121func (n *node) Warning(args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100122 n.logLeveled(0, WARNING, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200123}
124
125// Warningf implements the LeveledLogger interface.
126func (n *node) Warningf(format string, args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100127 n.logLeveled(0, WARNING, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200128}
129
130// Error implements the LeveledLogger interface.
131func (n *node) Error(args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100132 n.logLeveled(0, ERROR, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200133}
134
135// Errorf implements the LeveledLogger interface.
136func (n *node) Errorf(format string, args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100137 n.logLeveled(0, ERROR, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200138}
139
140// Fatal implements the LeveledLogger interface.
141func (n *node) Fatal(args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100142 n.logLeveled(0, FATAL, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200143}
144
145// Fatalf implements the LeveledLogger interface.
146func (n *node) Fatalf(format string, args ...interface{}) {
Serge Bazanskif68153c2020-10-26 13:54:37 +0100147 n.logLeveled(0, FATAL, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200148}
149
150// V implements the LeveledLogger interface.
151func (n *node) V(v VerbosityLevel) VerboseLeveledLogger {
152 return &verbose{
153 node: n,
154 enabled: n.verbosity >= v,
155 }
156}
157
158// verbose implements the VerboseLeveledLogger interface. It is a thin wrapper around node, with an 'enabled' bool. This
159// means that V(n)-returned VerboseLeveledLoggers must be short lived, as a changed in verbosity will not affect all
160// already existing VerboseLeveledLoggers.
161type verbose struct {
162 node *node
163 enabled bool
164}
165
166func (v *verbose) Enabled() bool {
167 return v.enabled
168}
169
170func (v *verbose) Info(args ...interface{}) {
171 if !v.enabled {
172 return
173 }
Serge Bazanskif68153c2020-10-26 13:54:37 +0100174 v.node.logLeveled(0, INFO, fmt.Sprint(args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200175}
176
177func (v *verbose) Infof(format string, args ...interface{}) {
178 if !v.enabled {
179 return
180 }
Serge Bazanskif68153c2020-10-26 13:54:37 +0100181 v.node.logLeveled(0, INFO, fmt.Sprintf(format, args...))
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200182}