Skip to content

yfuruyama/crzerolog

Repository files navigation

crzerolog

godoc CircleCI

A zerolog-based logging library for Cloud Run.

request log

Features

  • Auto format Cloud Logging fields such as time, severity, trace, sourceLocation
  • Groups application logs with the request log
  • Supports gRPC application on Cloud Run
  • Supports all of rs/zerolog APIs for structured logging

Installation

go get -u github.com/yfuruyama/crzerolog

Example for HTTP application

You just need to use crzerolog.InjectLogger to set up logging.

package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/yfuruyama/crzerolog"
)

func main() {
	rootLogger := zerolog.New(os.Stdout)
	middleware := crzerolog.InjectLogger(&rootLogger)

	http.Handle("/", middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logger := log.Ctx(r.Context())

		logger.Info().Msg("Hi")
		logger.Warn().Str("foo", "bar").Msg("This is")
		logger.Error().Int("num", 123).Msg("Structured Log")

		fmt.Fprintf(w, "Hello\n")
	})))

	port := "8080"
	if p := os.Getenv("PORT"); p != "" {
		port = p
	}
	log.Printf("Server listening on port %q", port)
	log.Fatal().Msg(http.ListenAndServe(":"+port, nil).Error())
}

After running above code on your Cloud Run service, you can find following logs in Cloud Logging.

Request Log

The request log is automatically written by Cloud Run. The log viewer shows correlated container logs in the same view.

request log

Container Logs

Container logs are written by this library. You can find that some Cloud Logging fields, such as severity, sourceLocation, timestamp, and trace are automatically set.

container log 1

If you add additional JSON fields to the log with zerolog APIs, those fields are contained in jsonPayload of the log.

container log 2

container log 3

Example for gRPC application

This library also supports gRPC application on Cloud Run.

You just need to use crzerolog.InjectLoggerInterceptor to set up logging.

package main

import (
	"context"
	"github.com/yfuruyama/crzerolog"
	"net"
	"os"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"google.golang.org/grpc"

	pb "github.com/yfuruyama/crzerolog/example/grpc/proto"
)

type server struct{}

func (s *server) Echo(ctx context.Context, r *pb.EchoRequest) (*pb.EchoReply, error) {
	logger := log.Ctx(ctx)

	logger.Info().Msg("Hi")
	logger.Warn().Str("foo", "bar").Msg("This is")
	logger.Error().Int("num", 123).Msg("Structured Log")

	return &pb.EchoReply{Msg: r.GetMsg() + "!"}, nil
}

func main() {
	port := "8080"
	if fromEnv := os.Getenv("PORT"); fromEnv != "" {
		port = fromEnv
	}

	l, err := net.Listen("tcp", ":"+port)
	if err != nil {
		log.Fatal().Msgf("Failed to listen: %v", err)
	}

	rootLogger := zerolog.New(os.Stdout)
	s := grpc.NewServer(
		grpc.UnaryInterceptor(crzerolog.InjectLoggerInterceptor(&rootLogger)),
	)
	pb.RegisterHelloServer(s, &server{})
	if err := s.Serve(l); err != nil {
		log.Fatal().Msgf("Failed to serve: %v", err)
	}
}

Level mapping

This library automatically maps zerolog level to Cloud Logging severity.

Mapping is as follows.

zerolog level Cloud Logging severity
NoLevel DEFAULT
TraceLevel DEFAULT
DebugLevel DEBUG
InfoLevel INFO
WarnLevel WARNING
ErrorLevel ERROR
FatalLevel CRITICAL
PanicLevel ALERT

Supported Platform

  • Cloud Run (fully managed) for HTTP and gRPC
  • Google App Engine (2nd-Generation) for HTTP

License

Apache 2.0.

Disclaimer

This is not an official Google product.