github.com/blend/go-sdk@v1.20240719.1/logger/context.go (about) 1 /* 2 3 Copyright (c) 2024 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package logger 9 10 import ( 11 "context" 12 "time" 13 ) 14 15 type loggerKey struct{} 16 17 // WithLogger adds the logger to a context. 18 func WithLogger(ctx context.Context, log Log) context.Context { 19 return context.WithValue(ctx, loggerKey{}, log) 20 } 21 22 // GetLogger gets a logger off a context. 23 func GetLogger(ctx context.Context) Log { 24 if value := ctx.Value(loggerKey{}); value != nil { 25 if typed, ok := value.(Log); ok { 26 return typed 27 } 28 } 29 return nil 30 } 31 32 type triggerTimestampKey struct{} 33 34 // WithTriggerTimestamp returns a new context with a given timestamp value. 35 // It is used by the scope to connote when an event was triggered. 36 func WithTriggerTimestamp(ctx context.Context, ts time.Time) context.Context { 37 return context.WithValue(ctx, triggerTimestampKey{}, ts) 38 } 39 40 // GetTriggerTimestamp gets when an event was triggered off a context. 41 func GetTriggerTimestamp(ctx context.Context) time.Time { 42 if raw := ctx.Value(triggerTimestampKey{}); raw != nil { 43 if typed, ok := raw.(time.Time); ok { 44 return typed 45 } 46 } 47 return time.Time{} 48 } 49 50 type timestampKey struct{} 51 52 // WithTimestamp returns a new context with a given timestamp value. 53 func WithTimestamp(ctx context.Context, ts time.Time) context.Context { 54 return context.WithValue(ctx, timestampKey{}, ts) 55 } 56 57 // GetTimestamp gets a timestampoff a context. 58 func GetTimestamp(ctx context.Context) time.Time { 59 if raw := ctx.Value(timestampKey{}); raw != nil { 60 if typed, ok := raw.(time.Time); ok { 61 return typed 62 } 63 } 64 return time.Time{} 65 } 66 67 type pathKey struct{} 68 69 // WithPath returns a new context with a given path segment(s). 70 // 71 // NOTE: This overwrites any _existing_ path context values. 72 // 73 // If you want to _append_ path segments, use `logger.WithPathAppend(...)`. 74 func WithPath(ctx context.Context, path ...string) context.Context { 75 return context.WithValue(ctx, pathKey{}, path) 76 } 77 78 // WithPathAppend appends a given path segment to a context. 79 func WithPathAppend(ctx context.Context, path ...string) context.Context { 80 return context.WithValue(ctx, pathKey{}, append(GetPath(ctx), path...)) 81 } 82 83 // GetPath gets a path off a context. 84 func GetPath(ctx context.Context) []string { 85 if raw := ctx.Value(pathKey{}); raw != nil { 86 if typed, ok := raw.([]string); ok { 87 return typed 88 } 89 } 90 return nil 91 } 92 93 type labelsKey struct{} 94 95 // WithSetLabels sets the labels on a context, overwriting any existing labels. 96 func WithSetLabels(ctx context.Context, labels Labels) context.Context { 97 return context.WithValue(ctx, labelsKey{}, labels) 98 } 99 100 // WithLabels returns a new context with a given additional labels. 101 // 102 // Any labels already on the context will be added to the new set 103 // with the provided set being layered on top of those. 104 func WithLabels(ctx context.Context, labels Labels) context.Context { 105 // it is critical here that we copy the labels 106 // and not mutate the existing map 107 combinedLabels := GetLabels(ctx) 108 for key, value := range labels { 109 combinedLabels[key] = value 110 } 111 return context.WithValue(ctx, labelsKey{}, combinedLabels) 112 } 113 114 // WithLabel returns a new context with a given additional label. 115 // 116 // Any labels already on the context will be added to the new set 117 // with the provided set being layered on top of those. 118 func WithLabel(ctx context.Context, key, value string) context.Context { 119 newLabels := make(Labels) 120 121 // it is critical here that we copy the labels 122 // and not mutate the existing map. 123 existing := GetLabels(ctx) 124 for key, value := range existing { 125 newLabels[key] = value 126 } 127 128 // we assign after as the new value should overwrite 129 newLabels[key] = value 130 return context.WithValue(ctx, labelsKey{}, newLabels) 131 } 132 133 // GetLabels gets labels off a context. 134 // 135 // It will return a copy of the labels, preventing map races. 136 func GetLabels(ctx context.Context) Labels { 137 if raw := ctx.Value(labelsKey{}); raw != nil { 138 if typed, ok := raw.(Labels); ok { 139 // create a copy 140 output := make(Labels) 141 for key, value := range typed { 142 output[key] = value 143 } 144 return output 145 } 146 } 147 return make(Labels) 148 } 149 150 // GetLabel gets a label off a context by key. 151 func GetLabel(ctx context.Context, key string) (string, bool) { 152 if raw := ctx.Value(labelsKey{}); raw != nil { 153 if typed, ok := raw.(Labels); ok { 154 if value, found := typed[key]; found { 155 return value, true 156 } 157 } 158 } 159 return "", false 160 } 161 162 type annotationsKey struct{} 163 164 // WithAnnotations returns a new context with a given additional annotations. 165 func WithAnnotations(ctx context.Context, annotations Annotations) context.Context { 166 return context.WithValue(ctx, annotationsKey{}, annotations) 167 } 168 169 // WithAnnotation returns a new context with a given additional annotation. 170 func WithAnnotation(ctx context.Context, key string, value interface{}) context.Context { 171 existing := GetAnnotations(ctx) 172 existing[key] = value 173 return context.WithValue(ctx, annotationsKey{}, existing) 174 } 175 176 // GetAnnotations gets annotations off a context. 177 func GetAnnotations(ctx context.Context) Annotations { 178 if raw := ctx.Value(annotationsKey{}); raw != nil { 179 if typed, ok := raw.(Annotations); ok { 180 // create a copy 181 output := make(Annotations) 182 for key, value := range typed { 183 output[key] = value 184 } 185 return output 186 } 187 } 188 return make(Annotations) 189 } 190 191 type restrictedKey struct{} 192 193 // WithRestricted returns a new context with the restricted value. 194 func WithRestricted(ctx context.Context, restricted bool) context.Context { 195 return context.WithValue(ctx, restrictedKey{}, restricted) 196 } 197 198 // GetRestricted gets restricted value from a context. 199 func GetRestricted(ctx context.Context) bool { 200 if raw := ctx.Value(restrictedKey{}); raw != nil { 201 if typed, ok := raw.(bool); ok { 202 return typed 203 } 204 } 205 return false 206 } 207 208 type skipTriggerKey struct{} 209 210 type skipWriteKey struct{} 211 212 // WithSkipTrigger sets the context to skip logger listener triggers. 213 // The event will still be written unless you also use `WithSkipWrite`. 214 func WithSkipTrigger(ctx context.Context, skipTrigger bool) context.Context { 215 return context.WithValue(ctx, skipTriggerKey{}, skipTrigger) 216 } 217 218 // WithSkipWrite sets the context to skip writing the event to the output stream. 219 // The event will still trigger listeners unless you also use `WithSkipTrigger`. 220 func WithSkipWrite(ctx context.Context, skipWrite bool) context.Context { 221 return context.WithValue(ctx, skipWriteKey{}, skipWrite) 222 } 223 224 // IsSkipTrigger returns if we should skip triggering logger listeners for a context. 225 func IsSkipTrigger(ctx context.Context) bool { 226 if v := ctx.Value(skipTriggerKey{}); v != nil { 227 if typed, ok := v.(bool); ok { 228 return typed 229 } 230 } 231 return false 232 } 233 234 // IsSkipWrite returns if we should skip writing to the event stream for a context. 235 func IsSkipWrite(ctx context.Context) bool { 236 if v := ctx.Value(skipWriteKey{}); v != nil { 237 if typed, ok := v.(bool); ok { 238 return typed 239 } 240 } 241 return false 242 }