# README

Correlation logging instructions

There are three ways for using this package. All methods will result in a correlation ID being added to the log lines. Each method may make sense in different scenarios. We've provided all three methods as they can be used interchangeably depending on the developers preference.

Currently, a correlation context is created as part of a gRPC interceptor for the following openstorage packages:

  • The CSI Driver (/csi)
  • The SDK Server (/api/server/sdk)

Method 1: Per-package correlation logger

This method is nice if a package maintainer wants to register a global logging hook at a per-package level. This is nice as you only need to create the logger once per package. However, each log line can be quite verbose as you must provide WithContext(ctx)

File 1:

package example

var (
    clogger := correlation.NewPackageLogger("test")
)
	
func testFunc(ctx context.Context ) {
    ctx := correlation.WithCorrelationContext(ctx, "source-component")

    clogger.WithContext(ctx).Info("test info log 1")
    testFuncTwo(ctx)
}

File 2:

package example

func testFuncTwo(ctx context.Context) {
    clogger.WithContext(ctx).Info("test info log 2")
}

Method 2: Per-function correlation logger

This method is great for reducing the amount of count needed per-line, as you do not need to pass in the context at every log line. However, you must remember to instantiate the logger at every function.

package example

func init() {
    // RegisterComponent registers the package where this function was called from
    // as a given component name.
    correlation.RegisterComponent("example-package")
}

func testFunc() {
    ctx := correlation.WithCorrelationContext(context.Background(), "test_origin")
    clogger := correlation.NewFunctionLogger(ctx)

    clogger.Info("test info log 1")
    testFuncTwo(ctx)
}

func testFuncTwo(ctx context.Context) {
    clogger := correlation.NewFunctionLogger(ctx)

    clogger.Info("test info log")
}

Method 3: Global correlation logging hook

This is a nice catch-all for covering packages where a package-level or function-level logger is not created. To mark certain packages as a component, call RegisterComponent from a given package. Each log line in this package will have the registered component added. If a package is not registered as a component, we'll find the component based on the package.

In main.go, first we should register the global hook:

package main

init() {
    // RegisterGlobalHook will register the correlation logging
    // hook at a global/multi-package level. Note that this is not
    // component-aware and it is better to use NewFunctionLogger
    // or NewPackageLogger for logging.
    correlation.RegisterGlobalHook()

    // RegisterComponent registers the package where this function was called from
    // as a given component name.
    correlation.RegisterComponent("main")
}

func main() {
    ...
}

In every other package, we can register components as we see fit.

This will help add extra context in our log lines for those who are unfamiliar with our codebase. For example, if a support engineer sees many log line failures with "csi-driver" component, they'll know who to contact regarding that failure.

The following example shows how a helper package can be registered as a component:

package example

func init() {
    // RegisterComponent registers the package where this function was called from
    // as a given component name.
    correlation.RegisterComponent("example-package")
}

func TestFuncTwo(ctx context.Context) {
    logrus.WithContext(ctx).Info("test info log 2")
}

# Functions

ContextUnaryClientInterceptor creates a gRPC interceptor for adding correlation ID to each request.
No description provided by the author
NewFunctionLogger creates a logger for usage at a per-function level For example, this logger can be instantiated inside of a function with a given context object.
NewPackageLogger creates a package-level logger for a given component.
RegisterComponent registers the package where this function was called from as a given component name.
RegisterGlobalHook will register the correlation logging hook at a global/multi-package level per-program.
RequestContextFromContextMetadata returns a new request context from a metadata object.
RequestContextFromContextValue returns the request context from a context value.
TODO is an alias for context.TODO(), specifically for keeping track of areas where we might want to add the correlation context.
WithCorrelationContext returns a new correlation context object.

# Constants

No description provided by the author
No description provided by the author
No description provided by the author
ContextIDKey represents the key for the correlation ID.
ContextKey represents the key for storing and retrieving the correlation context in a context.Context object.
ContextOriginKey represents the key for the correlation origin.
LogFieldComponent represents a logging field for control plane component.
LogFieldID represents a logging field for IDs.
LogFieldID represents a logging field for the request origin.

# Structs

ContextInterceptor represents a correlation interceptor.
No description provided by the author
RequestContext represents the context for a given a request.

# Type aliases

Component represents a control plane component for correlating requests.