2019-07-10 13:19:29 -06:00
|
|
|
// Copyright 2019 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Package log is a context based logging package, designed to interact well
|
|
|
|
// with both the lsp protocol and the other telemetry packages.
|
|
|
|
package log
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
|
2019-08-13 13:07:39 -06:00
|
|
|
"golang.org/x/tools/internal/telemetry/tag"
|
|
|
|
"golang.org/x/tools/internal/telemetry/worker"
|
2019-07-10 13:19:29 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// The well known tag keys for the logging system.
|
|
|
|
MessageTag = tag.Key("message")
|
|
|
|
ErrorTag = tag.Key("error")
|
|
|
|
)
|
|
|
|
|
|
|
|
// Logger is a function that handles logging messages.
|
|
|
|
// Loggers are registered at start up, and may use information in the context
|
|
|
|
// to decide what to do with a given log message.
|
|
|
|
type Logger func(ctx context.Context, at time.Time, tags tag.List) bool
|
|
|
|
|
|
|
|
// With sends a tag list to the installed loggers.
|
|
|
|
func With(ctx context.Context, tags ...tag.Tag) {
|
|
|
|
at := time.Now()
|
|
|
|
worker.Do(func() {
|
|
|
|
deliver(ctx, at, tags)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print takes a message and a tag list and combines them into a single tag
|
|
|
|
// list before delivering them to the loggers.
|
|
|
|
func Print(ctx context.Context, message string, tags ...tag.Tagger) {
|
|
|
|
at := time.Now()
|
|
|
|
worker.Do(func() {
|
|
|
|
tags := append(tag.Tags(ctx, tags...), MessageTag.Of(message))
|
|
|
|
deliver(ctx, at, tags)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
type errorString string
|
|
|
|
|
|
|
|
// Error allows errorString to conform to the error interface.
|
|
|
|
func (err errorString) Error() string { return string(err) }
|
|
|
|
|
|
|
|
// Print takes a message and a tag list and combines them into a single tag
|
|
|
|
// list before delivering them to the loggers.
|
|
|
|
func Error(ctx context.Context, message string, err error, tags ...tag.Tagger) {
|
|
|
|
at := time.Now()
|
|
|
|
worker.Do(func() {
|
|
|
|
if err == nil {
|
|
|
|
err = errorString(message)
|
|
|
|
message = ""
|
|
|
|
}
|
|
|
|
tags := append(tag.Tags(ctx, tags...), MessageTag.Of(message), ErrorTag.Of(err))
|
|
|
|
deliver(ctx, at, tags)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func deliver(ctx context.Context, at time.Time, tags tag.List) {
|
|
|
|
delivered := false
|
|
|
|
for _, logger := range loggers {
|
|
|
|
if logger(ctx, at, tags) {
|
|
|
|
delivered = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !delivered {
|
|
|
|
// no logger processed the message, so we log to stderr just in case
|
|
|
|
Stderr(ctx, at, tags)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var loggers = []Logger{}
|
|
|
|
|
|
|
|
func AddLogger(logger Logger) {
|
|
|
|
worker.Do(func() {
|
|
|
|
loggers = append(loggers, logger)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stderr is a logger that logs to stderr in the standard format.
|
|
|
|
func Stderr(ctx context.Context, at time.Time, tags tag.List) bool {
|
|
|
|
fmt.Fprintf(os.Stderr, "%v\n", ToEntry(ctx, at, tags))
|
|
|
|
return true
|
|
|
|
}
|
2019-08-13 11:35:13 -06:00
|
|
|
|
|
|
|
// NullLogger is a logger that throws away log messages and reports
|
|
|
|
// success so that the fallback stderr logging does not happen.
|
|
|
|
var NullLogger = func(context.Context, time.Time, tag.List) bool {
|
|
|
|
return true
|
|
|
|
}
|