1// +build go1.13 2 3// Copyright (c) Microsoft Corporation. All rights reserved. 4// Licensed under the MIT License. 5 6package azcore 7 8import ( 9 "fmt" 10 "os" 11 "time" 12) 13 14// LogClassification is used to group entries. Each group can be toggled on or off. 15type LogClassification string 16 17const ( 18 // LogRequest entries contain information about HTTP requests. 19 // This includes information like the URL, query parameters, and headers. 20 LogRequest LogClassification = "Request" 21 22 // LogResponse entries contain information about HTTP responses. 23 // This includes information like the HTTP status code, headers, and request URL. 24 LogResponse LogClassification = "Response" 25 26 // LogRetryPolicy entries contain information specific to the retry policy in use. 27 LogRetryPolicy LogClassification = "RetryPolicy" 28 29 // LogLongRunningOperation entries contain information specific to long-running operations. 30 // This includes information like polling location, operation state and sleep intervals. 31 LogLongRunningOperation LogClassification = "LongRunningOperation" 32) 33 34// Listener is the function signature invoked when writing log entries. 35// A Listener is required to perform its own synchronization if it's 36// expected to be called from multiple Go routines. 37type Listener func(LogClassification, string) 38 39// Logger controls which classifications to log and writing to the underlying log. 40type Logger struct { 41 cls []LogClassification 42 lst Listener 43} 44 45// SetClassifications is used to control which classifications are written to 46// the log. By default all log classifications are written. 47func (l *Logger) SetClassifications(cls ...LogClassification) { 48 l.cls = cls 49} 50 51// SetListener will set the Logger to write to the specified Listener. 52func (l *Logger) SetListener(lst Listener) { 53 l.lst = lst 54} 55 56// Should returns true if the specified log classification should be written to the log. 57// By default all log classifications will be logged. Call SetClassification() to limit 58// the log classifications for logging. 59// If no listener has been set this will return false. 60// Calling this method is useful when the message to log is computationally expensive 61// and you want to avoid the overhead if its log classification is not enabled. 62func (l *Logger) Should(cls LogClassification) bool { 63 if l.lst == nil { 64 return false 65 } 66 if l.cls == nil || len(l.cls) == 0 { 67 return true 68 } 69 for _, c := range l.cls { 70 if c == cls { 71 return true 72 } 73 } 74 return false 75} 76 77// Write invokes the underlying Listener with the specified classification and message. 78// If the classification shouldn't be logged or there is no listener then Write does nothing. 79func (l *Logger) Write(cls LogClassification, message string) { 80 if l.lst == nil || !l.Should(cls) { 81 return 82 } 83 l.lst(cls, message) 84} 85 86// Writef invokes the underlying Listener with the specified classification and formatted message. 87// If the classification shouldn't be logged or there is no listener then Writef does nothing. 88func (l *Logger) Writef(cls LogClassification, format string, a ...interface{}) { 89 if l.lst == nil || !l.Should(cls) { 90 return 91 } 92 l.lst(cls, fmt.Sprintf(format, a...)) 93} 94 95// for testing purposes 96func (l *Logger) resetClassifications() { 97 l.cls = nil 98} 99 100var logger Logger 101 102// Log returns the process-wide logger. 103func Log() *Logger { 104 return &logger 105} 106 107func init() { 108 if cls := os.Getenv("AZURE_SDK_GO_LOGGING"); cls == "all" { 109 // cls could be enhanced to support a comma-delimited list of log classifications 110 logger.lst = func(cls LogClassification, msg string) { 111 // simple console logger, it writes to stderr in the following format: 112 // [time-stamp] Classification: message 113 fmt.Fprintf(os.Stderr, "[%s] %s: %s\n", time.Now().Format(time.StampMicro), cls, msg) 114 } 115 } 116} 117