1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package logging 16 17 import ( 18 "context" 19 "io" 20 "os" 21 "time" 22 ) 23 24 // LoggerOption is a configuration option for a Logger. 25 type LoggerOption interface { 26 set(*Logger) 27 } 28 29 // CommonLabels are labels that apply to all log entries written from a Logger, 30 // so that you don't have to repeat them in each log entry's Labels field. If 31 // any of the log entries contains a (key, value) with the same key that is in 32 // CommonLabels, then the entry's (key, value) overrides the one in 33 // CommonLabels. 34 func CommonLabels(m map[string]string) LoggerOption { return commonLabels(m) } 35 36 type commonLabels map[string]string 37 38 func (c commonLabels) set(l *Logger) { l.commonLabels = c } 39 40 // ConcurrentWriteLimit determines how many goroutines will send log entries to the 41 // underlying service. The default is 1. Set ConcurrentWriteLimit to a higher value to 42 // increase throughput. 43 func ConcurrentWriteLimit(n int) LoggerOption { return concurrentWriteLimit(n) } 44 45 type concurrentWriteLimit int 46 47 func (c concurrentWriteLimit) set(l *Logger) { l.bundler.HandlerLimit = int(c) } 48 49 // DelayThreshold is the maximum amount of time that an entry should remain 50 // buffered in memory before a call to the logging service is triggered. Larger 51 // values of DelayThreshold will generally result in fewer calls to the logging 52 // service, while increasing the risk that log entries will be lost if the 53 // process crashes. 54 // The default is DefaultDelayThreshold. 55 func DelayThreshold(d time.Duration) LoggerOption { return delayThreshold(d) } 56 57 type delayThreshold time.Duration 58 59 func (d delayThreshold) set(l *Logger) { l.bundler.DelayThreshold = time.Duration(d) } 60 61 // EntryCountThreshold is the maximum number of entries that will be buffered 62 // in memory before a call to the logging service is triggered. Larger values 63 // will generally result in fewer calls to the logging service, while 64 // increasing both memory consumption and the risk that log entries will be 65 // lost if the process crashes. 66 // The default is DefaultEntryCountThreshold. 67 func EntryCountThreshold(n int) LoggerOption { return entryCountThreshold(n) } 68 69 type entryCountThreshold int 70 71 func (e entryCountThreshold) set(l *Logger) { l.bundler.BundleCountThreshold = int(e) } 72 73 // EntryByteThreshold is the maximum number of bytes of entries that will be 74 // buffered in memory before a call to the logging service is triggered. See 75 // EntryCountThreshold for a discussion of the tradeoffs involved in setting 76 // this option. 77 // The default is DefaultEntryByteThreshold. 78 func EntryByteThreshold(n int) LoggerOption { return entryByteThreshold(n) } 79 80 type entryByteThreshold int 81 82 func (e entryByteThreshold) set(l *Logger) { l.bundler.BundleByteThreshold = int(e) } 83 84 // EntryByteLimit is the maximum number of bytes of entries that will be sent 85 // in a single call to the logging service. ErrOversizedEntry is returned if an 86 // entry exceeds EntryByteLimit. This option limits the size of a single RPC 87 // payload, to account for network or service issues with large RPCs. If 88 // EntryByteLimit is smaller than EntryByteThreshold, the latter has no effect. 89 // The default is zero, meaning there is no limit. 90 func EntryByteLimit(n int) LoggerOption { return entryByteLimit(n) } 91 92 type entryByteLimit int 93 94 func (e entryByteLimit) set(l *Logger) { l.bundler.BundleByteLimit = int(e) } 95 96 // BufferedByteLimit is the maximum number of bytes that the Logger will keep 97 // in memory before returning ErrOverflow. This option limits the total memory 98 // consumption of the Logger (but note that each Logger has its own, separate 99 // limit). It is possible to reach BufferedByteLimit even if it is larger than 100 // EntryByteThreshold or EntryByteLimit, because calls triggered by the latter 101 // two options may be enqueued (and hence occupying memory) while new log 102 // entries are being added. 103 // The default is DefaultBufferedByteLimit. 104 func BufferedByteLimit(n int) LoggerOption { return bufferedByteLimit(n) } 105 106 type bufferedByteLimit int 107 108 func (b bufferedByteLimit) set(l *Logger) { l.bundler.BufferedByteLimit = int(b) } 109 110 // ContextFunc is a function that will be called to obtain a context.Context for the 111 // WriteLogEntries RPC executed in the background for calls to Logger.Log. The 112 // default is a function that always returns context.Background. The second return 113 // value of the function is a function to call after the RPC completes. 114 // 115 // The function is not used for calls to Logger.LogSync, since the caller can pass 116 // in the context directly. 117 // 118 // This option is EXPERIMENTAL. It may be changed or removed. 119 func ContextFunc(f func() (ctx context.Context, afterCall func())) LoggerOption { 120 return contextFunc(f) 121 } 122 123 type contextFunc func() (ctx context.Context, afterCall func()) 124 125 func (c contextFunc) set(l *Logger) { l.ctxFunc = c } 126 127 // SourceLocationPopulation is the flag controlling population of the source location info 128 // in the ingested entries. This options allows to configure automatic population of the 129 // SourceLocation field for all ingested entries, entries with DEBUG severity or disable it. 130 // Note that enabling this option can decrease execution time of Logger.Log and Logger.LogSync 131 // by the factor of 2 or larger. 132 // The default disables source location population. 133 // 134 // This option is not used when an entry is created using ToLogEntry. 135 func SourceLocationPopulation(f int) LoggerOption { 136 return sourceLocationOption(f) 137 } 138 139 const ( 140 // DoNotPopulateSourceLocation is default for clients when WithSourceLocation is not provided 141 DoNotPopulateSourceLocation = 0 142 // PopulateSourceLocationForDebugEntries is set when WithSourceLocation(PopulateDebugEntries) is provided 143 PopulateSourceLocationForDebugEntries = 1 144 // AlwaysPopulateSourceLocation is set when WithSourceLocation(PopulateAllEntries) is provided 145 AlwaysPopulateSourceLocation = 2 146 ) 147 148 type sourceLocationOption int 149 150 func (o sourceLocationOption) set(l *Logger) { 151 if o == DoNotPopulateSourceLocation || o == PopulateSourceLocationForDebugEntries || o == AlwaysPopulateSourceLocation { 152 l.populateSourceLocation = int(o) 153 } 154 } 155 156 // PartialSuccess sets the partialSuccess flag to true when ingesting a bundle of log entries. 157 // See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write#body.request_body.FIELDS.partial_success 158 // If not provided the partialSuccess flag is set to false. 159 func PartialSuccess() LoggerOption { 160 return &partialSuccessOption{} 161 } 162 163 type partialSuccessOption struct{} 164 165 func (o *partialSuccessOption) set(l *Logger) { 166 l.partialSuccess = true 167 } 168 169 // RedirectAsJSON instructs Logger to redirect output of calls to Log and LogSync to provided io.Writer instead of ingesting 170 // to Cloud Logging. Logger formats log entries following logging agent's Json format. 171 // See https://cloud.google.com/logging/docs/structured-logging#special-payload-fields for more info about the format. 172 // Use this option to delegate log ingestion to an out-of-process logging agent. 173 // If no writer is provided, the redirect is set to stdout. 174 func RedirectAsJSON(w io.Writer) LoggerOption { 175 if w == nil { 176 w = os.Stdout 177 } 178 return &redirectOutputOption{ 179 writer: w, 180 } 181 } 182 183 type redirectOutputOption struct { 184 writer io.Writer 185 } 186 187 func (o *redirectOutputOption) set(l *Logger) { 188 l.redirectOutputWriter = o.writer 189 } 190