correlation

package
v10.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 12, 2022 License: Apache-2.0 Imports: 9 Imported by: 0

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")
}

Documentation

Overview

Copyright 2021 Portworx

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Index

Constants

View Source
const (
	// ContextKey represents the key for storing and retrieving
	// the correlation context in a context.Context object.
	ContextKey = contextKeyType("correlation-context")

	// ContextIDKey represents the key for the correlation ID
	ContextIDKey = "correlation-context-id"

	// ContextOriginKey represents the key for the correlation origin
	ContextOriginKey = "correlation-context-origin"

	ComponentUnknown   = Component("unknown")
	ComponentCSIDriver = Component("csi-driver")
	ComponentSDK       = Component("sdk-server")
	ComponentAuth      = Component("openstorage/pkg/auth")
)
View Source
const (
	// LogFieldID represents a logging field for IDs
	LogFieldID = "correlation-id"
	// LogFieldID represents a logging field for the request origin
	LogFieldOrigin = "origin"
	// LogFieldComponent represents a logging field for control plane component.
	// This is typically set per-package and allows you see which component
	// the log originated from.
	LogFieldComponent = "component"
)

Variables

This section is empty.

Functions

func ContextUnaryClientInterceptor

func ContextUnaryClientInterceptor(
	ctx context.Context,
	method string,
	req, reply interface{},
	cc *grpc.ClientConn,
	invoker grpc.UnaryInvoker,
	opts ...grpc.CallOption,
) error

ContextUnaryClientInterceptor creates a gRPC interceptor for adding correlation ID to each request

func NewFunctionLogger

func NewFunctionLogger(ctx context.Context) *logrus.Logger

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. As logs are printed, they will automatically include the correlation context info.

func NewPackageLogger

func NewPackageLogger(component Component) *logrus.Logger

NewPackageLogger creates a package-level logger for a given component

func RegisterComponent

func RegisterComponent(component Component)

RegisterComponent registers the package where this function was called from as a given component name. This should be done once per package where you want explicitly name the component for this package. Otherwise, we will detect the component based on package directory.

func RegisterGlobalHook

func RegisterGlobalHook()

RegisterGlobalHook will register the correlation logging hook at a global/multi-package level per-program.

func TODO

func TODO() context.Context

TODO is an alias for context.TODO(), specifically for keeping track of areas where we might want to add the correlation context.

func WithCorrelationContext

func WithCorrelationContext(ctx context.Context, origin Component) context.Context

WithCorrelationContext returns a new correlation context object

Types

type Component

type Component string

Component represents a control plane component for correlating requests

type ContextInterceptor

type ContextInterceptor struct {
	Origin Component
}

ContextInterceptor represents a correlation interceptor

func (*ContextInterceptor) ContextUnaryServerInterceptor

func (ci *ContextInterceptor) ContextUnaryServerInterceptor(
	ctx context.Context,
	req interface{},
	info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler,
) (interface{}, error)

ContextUnaryServerInterceptor creates a gRPC interceptor for adding correlation ID to each request

type LogHook

type LogHook struct {
	Component       Component
	FunctionContext context.Context
}

func (*LogHook) Fire

func (lh *LogHook) Fire(entry *logrus.Entry) error

Fire is used to add correlation context info in each log line

func (*LogHook) Levels

func (lh *LogHook) Levels() []logrus.Level

Levels describes which levels this logrus hook should run with.

type RequestContext

type RequestContext struct {
	// ID is a randomly generated UUID per requst
	ID string

	// Origin is the starting point for this request.
	// Examples may include any of the following:
	// pxctl, pxc, kubernetes, CSI, SDK, etc
	Origin Component
}

RequestContext represents the context for a given a request. A request represents a single action received from an SDK user, container orchestrator, or any other request.

func RequestContextFromContextMetadata

func RequestContextFromContextMetadata(md metadata.MD) *RequestContext

RequestContextFromContextMetadata returns a new request context from a metadata object

func RequestContextFromContextValue

func RequestContextFromContextValue(ctx context.Context) *RequestContext

RequestContextFromContextValue returns the request context from a context value

func (*RequestContext) AsMap

func (rc *RequestContext) AsMap() map[string]string

AsMap returns the request context as a map

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL