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  }