Add 'sdk/java-v2/' from commit '55f103e336ca9fb8bf1720d2ef4ee8dd4e221118'
[arvados.git] / sdk / go / ctxlog / log.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package ctxlog
6
7 import (
8         "bytes"
9         "context"
10         "io"
11         "os"
12
13         "github.com/sirupsen/logrus"
14         check "gopkg.in/check.v1"
15 )
16
17 var (
18         loggerCtxKey = new(int)
19         rootLogger   = logrus.New()
20 )
21
22 const rfc3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
23
24 // Context returns a new child context such that FromContext(child)
25 // returns the given logger.
26 func Context(ctx context.Context, logger logrus.FieldLogger) context.Context {
27         return context.WithValue(ctx, loggerCtxKey, logger)
28 }
29
30 // FromContext returns the logger suitable for the given context -- the one
31 // attached by contextWithLogger() if applicable, otherwise the
32 // top-level logger with no fields/values.
33 func FromContext(ctx context.Context) logrus.FieldLogger {
34         if ctx != nil {
35                 if logger, ok := ctx.Value(loggerCtxKey).(logrus.FieldLogger); ok {
36                         return logger
37                 }
38         }
39         return rootLogger.WithFields(nil)
40 }
41
42 // New returns a new logger with the indicated format and
43 // level.
44 func New(out io.Writer, format, level string) logrus.FieldLogger {
45         logger := logrus.New()
46         logger.Out = out
47         setFormat(logger, format)
48         setLevel(logger, level)
49         return logger
50 }
51
52 func TestLogger(c *check.C) logrus.FieldLogger {
53         logger := logrus.New()
54         logger.Out = &logWriter{c.Log}
55         setFormat(logger, "text")
56         if d := os.Getenv("ARVADOS_DEBUG"); d != "0" && d != "" {
57                 setLevel(logger, "debug")
58         } else {
59                 setLevel(logger, "info")
60         }
61         return logger
62 }
63
64 // SetLevel sets the current logging level. See logrus for level
65 // names.
66 func SetLevel(level string) {
67         setLevel(rootLogger, level)
68 }
69
70 func setLevel(logger *logrus.Logger, level string) {
71         if level == "" {
72         } else if lvl, err := logrus.ParseLevel(level); err != nil {
73                 logrus.WithField("Level", level).Fatal("unknown log level")
74         } else {
75                 logger.Level = lvl
76         }
77 }
78
79 // SetFormat sets the current logging format to "json" or "text".
80 func SetFormat(format string) {
81         setFormat(rootLogger, format)
82 }
83
84 func setFormat(logger *logrus.Logger, format string) {
85         switch format {
86         case "text":
87                 logger.Formatter = &logrus.TextFormatter{
88                         FullTimestamp:   true,
89                         TimestampFormat: rfc3339NanoFixed,
90                 }
91         case "json", "":
92                 logger.Formatter = &logrus.JSONFormatter{
93                         TimestampFormat: rfc3339NanoFixed,
94                 }
95         default:
96                 logrus.WithField("Format", format).Fatal("unknown log format")
97         }
98 }
99
100 // logWriter is an io.Writer that writes by calling a "write log"
101 // function, typically (*check.C)Log().
102 type logWriter struct {
103         logfunc func(...interface{})
104 }
105
106 func (tl *logWriter) Write(buf []byte) (int, error) {
107         tl.logfunc(string(bytes.TrimRight(buf, "\n")))
108         return len(buf), nil
109 }