grpc-ecosystem / go-grpc-middleware

Golang gRPC Middlewares: interceptor chaining, auth, logging, retries and more.
Apache License 2.0
6.26k stars 690 forks source link

go-grpc-middleware/providers/openmetrics/v2 v2.0.0-rc.3 dependency of go-grpc-middleware/v2 v2.0.1 broken #683

Closed RogerioWagner closed 9 months ago

RogerioWagner commented 9 months ago

go 1.21.4

go.mod snippet

require (
        ...
    github.com/grpc-ecosystem/go-grpc-middleware/providers/openmetrics/v2 v2.0.0-rc.3
    github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1
        ...
)

openmetrics v2.0.0-rc.3 reporter.go snippet

import (
    "context"
    "time"

    openmetrics "github.com/prometheus/client_golang/prometheus"

    "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors"
)

type reporter struct {
    clientMetrics           *ClientMetrics
    serverMetrics           *ServerMetrics
    typ                     interceptors.GRPCType
    service, method         string
    startTime               time.Time
    kind                    Kind
    sendTimer, receiveTimer interceptors.Timer
}

What happened:

~/go/pkg/mod/github.com/grpc-ecosystem/go-grpc-middleware/providers/openmetrics/v2@v2.0.0-rc.3/reporter.go:22:39: undefined: interceptors.Timer ~/go/pkg/mod/github.com/grpc-ecosystem/go-grpc-middleware/providers/openmetrics/v2@v2.0.0-rc.3/reporter.go:87:31: undefined: interceptors.EmptyTimer ~/go/pkg/mod/github.com/grpc-ecosystem/go-grpc-middleware/providers/openmetrics/v2@v2.0.0-rc.3/reporter.go:88:31: undefined: interceptors.EmptyTimer

What you expected to happen:

Build and run when github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 is used.

How to reproduce it (as minimally and precisely as possible):

Register and Configure Prometheus using package github.com/grpc-ecosystem/go-grpc-middleware/providers/openmetrics/v2

The fix seems simply to publish openmetrics v2.0.1 package, the package v2.0.0-rc.3 is the latest published https://pkg.go.dev/github.com/grpc-ecosystem/go-grpc-middleware/providers/openmetrics/v2@v2.0.0-rc.3 -->

The reason I would like to use package github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1, is LoggerFunc() available at Logging interceptor to configure and use slog as interceptor logger.

johanbrandhorst commented 9 months ago

I just pushed https://github.com/grpc-ecosystem/go-grpc-middleware/releases/tag/providers%2Fopenmetrics%2Fv2.0.1, does that work?

RogerioWagner commented 9 months ago

@johanbrandhorst Thank You, very much for your help.

I think the package is not available yet, go get failed and at pkg.go.dev still list rc3 as the latest package.

go get go-grpc-middleware-providers-openmetrics-v2.0.1                                                                                          ─╯

go: unrecognized import path "go-grpc-middleware-providers-openmetrics-v2.0.1": https fetch: Get "https://go-grpc-middleware-providers-openmetrics-v2.0.1/?go-get=1": dial tcp: lookup go-grpc-middleware-providers-openmetrics-v2.0.1: no such host
johanbrandhorst commented 9 months ago

Oops, looks like we removed that folder before tagging v2, I can't see it on the main branch. @bwplotka what happened to openmetrics?

bwplotka commented 9 months ago

Hey, it got renamed to Prometheus provider: https://github.com/grpc-ecosystem/go-grpc-middleware/tree/main/providers/prometheus , calling it open metrics was a mistake there, sorry.

Just replace it with a prometheus provider module should work for you (it has a different version than the main module, see https://github.com/grpc-ecosystem/go-grpc-middleware/releases/tag/providers%2Fprometheus%2Fv1.0.0).

bwplotka commented 9 months ago

Get and reference the prometheus provider module via go get github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus

RogerioWagner commented 9 months ago

@johanbrandhorst and @bwplotka Thank you very much Guys!

I've changed to prometheus package and referenced v2.0.1 of main package, it build correctly and worked with slog.

bwplotka commented 9 months ago

Epic! Do you mind sharing your slog integration? How your integrated roughly?

RogerioWagner commented 9 months ago

Sure, I have no credit on the implementation, basically I just followed the other logging interceptors, I may tweak it a little bit later, but for now I'm prioritizing the simplicity.

I've removed some lines to make it clear.

InterceptorLogger implementation

import (
    "context"
    "fmt"
    "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
    log "log/slog"
)

// InterceptorLogger function
func InterceptorLogger(l *log.Logger) logging.Logger {
    return logging.LoggerFunc(func(ctx context.Context, lvl logging.Level, msg string, fields ...any) {
        l.Log(ctx, log.Level(lvl), msg, fields...)
    })
}

Logging Options

        loggingOpts := []logging.Option{
            logging.WithLogOnEvents(logging.StartCall, logging.FinishCall, 
                                      logging.PayloadReceived, logging.PayloadSent),

        }

Added it to the Chain of Responsibility, log.Default returns the slog singleton previously configured

        // Create gRPC server with slog, prometheus, and panic recovery middleware
        srv := grpc.NewServer(
            grpc.ChainUnaryInterceptor(
                logging.UnaryServerInterceptor(InterceptorLogger(log.Default()), loggingOpts...),
                promGrpcServerMetrics.UnaryServerInterceptor(),
                recovery.UnaryServerInterceptor(),
            ),
            grpc.ChainStreamInterceptor(
                logging.StreamServerInterceptor(InterceptorLogger(log.Default()), loggingOpts...),
                promGrpcServerMetrics.StreamServerInterceptor(),
                recovery.StreamServerInterceptor(),
            ),
        )

A call to the Unary rpc method produced the bellow lines (non sensitive data)

{"time":"2023-12-05T16:16:13.460813-03:00","level":"INFO","msg":"started call","protocol":"grpc","grpc.component":"server","grpc.service":"nocloud.authentication.oauth.v1.OpenIdConfiguration","grpc.method":"discovery","grpc.method_type":"unary","peer.address":"[::1]:62072","grpc.start_time":"2023-12-05T16:16:13-03:00","grpc.time_ms":"0.027"}
{"time":"2023-12-05T16:16:13.460865-03:00","level":"INFO","msg":"request received","protocol":"grpc","grpc.component":"server","grpc.service":"nocloud.authentication.oauth.v1.OpenIdConfiguration","grpc.method":"discovery","grpc.method_type":"unary","peer.address":"[::1]:62072","grpc.start_time":"2023-12-05T16:16:13-03:00","grpc.recv.duration":"27.708µs","grpc.request.content":{}}
{"time":"2023-12-05T16:16:13.461066-03:00","level":"INFO","msg":"response sent","protocol":"grpc","grpc.component":"server","grpc.service":"nocloud.authentication.oauth.v1.OpenIdConfiguration","grpc.method":"discovery","grpc.method_type":"unary","peer.address":"[::1]:62072","grpc.start_time":"2023-12-05T16:16:13-03:00","grpc.send.duration":"319.166µs","grpc.response.content":{"jwksUri":"http://localhost:8080/.well-known/openid-configuration/jwks"}}
{"time":"2023-12-05T16:16:13.461301-03:00","level":"INFO","msg":"finished call","protocol":"grpc","grpc.component":"server","grpc.service":"nocloud.authentication.oauth.v1.OpenIdConfiguration","grpc.method":"discovery","grpc.method_type":"unary","peer.address":"[::1]:62072","grpc.start_time":"2023-12-05T16:16:13-03:00","grpc.code":"OK","grpc.time_ms":"0.554"}