1// Copyright (C) MongoDB, Inc. 2014-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7// Package log provides a utility to log timestamped messages to an io.Writer.
8package log
9
10import (
11	"fmt"
12	"io"
13	"os"
14	"sync"
15	"time"
16)
17
18// Tool Logger verbosity constants
19const (
20	Always = iota
21	Info
22	DebugLow
23	DebugHigh
24)
25
26const (
27	ToolTimeFormat = "2006-01-02T15:04:05.000-0700"
28)
29
30//// Tool Logger Definition
31
32type ToolLogger struct {
33	mutex     *sync.Mutex
34	writer    io.Writer
35	format    string
36	verbosity int
37}
38
39type VerbosityLevel interface {
40	Level() int
41	IsQuiet() bool
42}
43
44func (tl *ToolLogger) SetVerbosity(level VerbosityLevel) {
45	if level == nil {
46		tl.verbosity = 0
47		return
48	}
49
50	if level.IsQuiet() {
51		tl.verbosity = -1
52	} else {
53		tl.verbosity = level.Level()
54	}
55}
56
57func (tl *ToolLogger) SetWriter(writer io.Writer) {
58	tl.writer = writer
59}
60
61func (tl *ToolLogger) SetDateFormat(dateFormat string) {
62	tl.format = dateFormat
63}
64
65func (tl *ToolLogger) Logvf(minVerb int, format string, a ...interface{}) {
66	if minVerb < 0 {
67		panic("cannot set a minimum log verbosity that is less than 0")
68	}
69
70	if minVerb <= tl.verbosity {
71		tl.mutex.Lock()
72		defer tl.mutex.Unlock()
73		tl.log(fmt.Sprintf(format, a...))
74	}
75}
76
77func (tl *ToolLogger) Logv(minVerb int, msg string) {
78	if minVerb < 0 {
79		panic("cannot set a minimum log verbosity that is less than 0")
80	}
81
82	if minVerb <= tl.verbosity {
83		tl.mutex.Lock()
84		defer tl.mutex.Unlock()
85		tl.log(msg)
86	}
87}
88
89func (tl *ToolLogger) log(msg string) {
90	fmt.Fprintf(tl.writer, "%v\t%v\n", time.Now().Format(tl.format), msg)
91}
92
93func NewToolLogger(verbosity VerbosityLevel) *ToolLogger {
94	tl := &ToolLogger{
95		mutex:  &sync.Mutex{},
96		writer: os.Stderr, // default to stderr
97		format: ToolTimeFormat,
98	}
99	tl.SetVerbosity(verbosity)
100	return tl
101}
102
103//// Log Writer Interface
104
105// toolLogWriter is an io.Writer wrapping a tool logger. It is a private
106// type meant for creation with the ToolLogger.Writer(...) method.
107type toolLogWriter struct {
108	logger       *ToolLogger
109	minVerbosity int
110}
111
112func (tlw *toolLogWriter) Write(message []byte) (int, error) {
113	tlw.logger.Logv(tlw.minVerbosity, string(message))
114	return len(message), nil
115}
116
117// Writer returns an io.Writer that writes to the logger with
118// the given verbosity
119func (tl *ToolLogger) Writer(minVerb int) io.Writer {
120	return &toolLogWriter{tl, minVerb}
121}
122
123//// Global Logging
124
125var globalToolLogger *ToolLogger
126
127func init() {
128	if globalToolLogger == nil {
129		// initialize tool logger with verbosity level = 0
130		globalToolLogger = NewToolLogger(nil)
131	}
132}
133
134// IsInVerbosity returns true if the current verbosity level setting is
135// greater than or equal to the given level.
136func IsInVerbosity(minVerb int) bool {
137	return minVerb <= globalToolLogger.verbosity
138}
139
140func Logvf(minVerb int, format string, a ...interface{}) {
141	globalToolLogger.Logvf(minVerb, format, a...)
142}
143
144func Logv(minVerb int, msg string) {
145	globalToolLogger.Logv(minVerb, msg)
146}
147
148func SetVerbosity(verbosity VerbosityLevel) {
149	globalToolLogger.SetVerbosity(verbosity)
150}
151
152func SetWriter(writer io.Writer) {
153	globalToolLogger.SetWriter(writer)
154}
155
156func SetDateFormat(dateFormat string) {
157	globalToolLogger.SetDateFormat(dateFormat)
158}
159
160func Writer(minVerb int) io.Writer {
161	return globalToolLogger.Writer(minVerb)
162}
163