Skip to content

Nullify-Platform/Logger

Repository files navigation

Nullify Logging Library

Abstraction above the Uber Zap logging library so we aren't locked into a particular logger. Provides some standard logging practices across all Nullify services.

How do I use this?

To make the most use of this library, you have to ensure that your service passes context down within each function call.

One big change is that the logger is no longer a global variable. It is now linked to the context, so you need to ensure that you pass the context.

logger.L(ctx).Info("this is a log message")

First, declare the background context in your main function, and then inject the logger into the context.

func main() {
  ctx := context.Background()
  ctx, err := logger.ConfigureProductionLogger(ctx, "info") // inject logger into context

  // There is no longer a global logger. It is always linked to the context, to ensure that log messages have the appropriate span and trace IDs linked to them.
  defer logger.L(ctx).Sync() // defer the sync of the logger to ensure all logs are written

  // Initiate a new span, and defer ending the span to record the end of this piece of work.
  ctx, span := tracer.FromContext(ctx).Start(ctx, "main")
  defer span.End()


  // You can add more contextual event information to spans through the span.AddEvent method. This is analogous to adding a log message, and has an associated timestamp that is recorded.
  span.AddEvent("a piece of work is starting within the span")

  // You can also set attributes to the span to provide more context to the span, typically as key-value pairs.
  span.SetAttributes(
    attribute.String("customer-id", "018e4fc1-c079-70ce-84a0-9591295d96aa"),
    attribute.Int64("request-count", 80),
  )

  // You need to ensure that you pass context to other functions so that the logger and tracer are available to them.
  anotherFunction(ctx)
}

func anotherFunction(ctx context.Context) {
  // Retrieve the tracer from the context
  ctx, span := tracer.FromContext(ctx).Start(ctx, "some-other-work")
  defer span.End()

  // This will automatically set the parent function span to be the parent span of this new span that has started, within this trace.

  // To record errors, you can use the logger.L(ctx).Error() call. This will automatically capture any errors that you pass into it and pass them to GlitchTip. It will also set the span to errored, so it is highlighted in Grafana.

  error := errors.New("this is an error")
  logger.L(err).Error("this is an error", error)
}

Error Collection

To collect errors and send them to GlitchTip, you have to set the SENTRY_DSN environment variable.

OpenTelemetry Exporting

To actually have your traces exported, you need to set a few environment variables in your service:

  • OTEL_EXPORTER_OTLP_PROTOCOL: typically set to http/protobuf; this is the protocol that the traces are sent over.
  • OTEL_EXPORTER_OTLP_ENDPOINT: the endpoint that the traces are sent to.
  • OTEL_EXPORTER_OTLP_HEADERS_NAME: the name of the parameter in aws parameter store that contains the headers for the OTLP exporter.
  • OTEL_RESOURCE_ATTRIBUTES: the attributes that are associated with the service. Typically, you would set the environment here like deployment.environment=production.
  • OTEL_SERVICE_NAME: the name of the service that is being traced.

Install

Dependencies:

  • make
  • golang

Install code dependencies

go mod download

Build

Compile the code locally into the bin directory

make

Test

make test # without coverage
make cov  # with coverage

Lint

Run the golangci-lint docker image with the following tools:

  • gofmt
  • stylecheck
  • gosec
make lint