github.com/blend/go-sdk@v1.20220411.3/logger/context.go (about) 1 /* 2 3 Copyright (c) 2022 - 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 type annotationsKey struct{} 151 152 // WithAnnotations returns a new context with a given additional annotations. 153 func WithAnnotations(ctx context.Context, annotations Annotations) context.Context { 154 return context.WithValue(ctx, annotationsKey{}, annotations) 155 } 156 157 // WithAnnotation returns a new context with a given additional annotation. 158 func WithAnnotation(ctx context.Context, key string, value interface{}) context.Context { 159 existing := GetAnnotations(ctx) 160 existing[key] = value 161 return context.WithValue(ctx, annotationsKey{}, existing) 162 } 163 164 // GetAnnotations gets annotations off a context. 165 func GetAnnotations(ctx context.Context) Annotations { 166 if raw := ctx.Value(annotationsKey{}); raw != nil { 167 if typed, ok := raw.(Annotations); ok { 168 // create a copy 169 output := make(Annotations) 170 for key, value := range typed { 171 output[key] = value 172 } 173 return output 174 } 175 } 176 return make(Annotations) 177 } 178 179 type skipTriggerKey struct{} 180 181 type skipWriteKey struct{} 182 183 // WithSkipTrigger sets the context to skip logger listener triggers. 184 // The event will still be written unless you also use `WithSkipWrite`. 185 func WithSkipTrigger(ctx context.Context, skipTrigger bool) context.Context { 186 return context.WithValue(ctx, skipTriggerKey{}, skipTrigger) 187 } 188 189 // WithSkipWrite sets the context to skip writing the event to the output stream. 190 // The event will still trigger listeners unless you also use `WithSkipTrigger`. 191 func WithSkipWrite(ctx context.Context, skipWrite bool) context.Context { 192 return context.WithValue(ctx, skipWriteKey{}, skipWrite) 193 } 194 195 // IsSkipTrigger returns if we should skip triggering logger listeners for a context. 196 func IsSkipTrigger(ctx context.Context) bool { 197 if v := ctx.Value(skipTriggerKey{}); v != nil { 198 if typed, ok := v.(bool); ok { 199 return typed 200 } 201 } 202 return false 203 } 204 205 // IsSkipWrite returns if we should skip writing to the event stream for a context. 206 func IsSkipWrite(ctx context.Context) bool { 207 if v := ctx.Value(skipWriteKey{}); v != nil { 208 if typed, ok := v.(bool); ok { 209 return typed 210 } 211 } 212 return false 213 }