Added observability to the system.

This commit is contained in:
Mariano Uvalle 2021-08-13 14:46:01 -05:00
parent 64e6faecae
commit 21dcda4a9a
4 changed files with 117 additions and 38 deletions

View file

@ -2,11 +2,19 @@ package server
import (
"context"
"time"
api "github.com/AYM1607/proglog/api/v1"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
@ -29,15 +37,40 @@ type Config struct {
var _ api.LogServer = (*grpcServer)(nil)
func NewGRPCServer(config *Config, opts ...grpc.ServerOption) (*grpc.Server, error) {
// Logging.
logger := zap.L().Named("server")
zapOpts := []grpc_zap.Option{
grpc_zap.WithDurationField(
func(duration time.Duration) zapcore.Field {
return zap.Int64(
"grpc.time_ns",
duration.Nanoseconds(),
)
},
),
}
// Tracing.
// This should not be used in production and a better sampler should be written.
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
err := view.Register(ocgrpc.DefaultServerViews...)
if err != nil {
return nil, err
}
opts = append(opts,
// Streaming interceptors.
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
grpc_ctxtags.StreamServerInterceptor(),
grpc_zap.StreamServerInterceptor(logger, zapOpts...),
grpc_auth.StreamServerInterceptor(authenticate),
)),
// Unary interceptors.
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
grpc_ctxtags.UnaryServerInterceptor(),
grpc_zap.UnaryServerInterceptor(logger, zapOpts...),
grpc_auth.UnaryServerInterceptor(authenticate),
)),
grpc.StatsHandler(&ocgrpc.ServerHandler{}),
)
gsrv := grpc.NewServer(opts...)
srv, err := newgrpcServer(config)

View file

@ -2,21 +2,40 @@ package server
import (
"context"
"flag"
"io/ioutil"
"net"
"os"
"testing"
"time"
api "github.com/AYM1607/proglog/api/v1"
"github.com/AYM1607/proglog/internal/auth"
"github.com/AYM1607/proglog/internal/config"
"github.com/AYM1607/proglog/internal/log"
"github.com/stretchr/testify/require"
"go.opencensus.io/examples/exporter"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/status"
)
var debug = flag.Bool("debug", false, "Enable observability for debugging.")
func TestMain(m *testing.M) {
flag.Parse()
if *debug {
logger, err := zap.NewDevelopment()
if err != nil {
panic(err)
}
zap.ReplaceGlobals(logger)
}
os.Exit(m.Run())
}
func TestServer(t *testing.T) {
for scenario, fn := range map[string]func(
t *testing.T,
@ -72,34 +91,60 @@ func setupTest(t *testing.T, fn func(*Config)) (
return conn, client, opts
}
rootConn, rootClient, _ := newClient(
// TODO: research relation of closures and shorthand variable declaration.
// If the connection is on created with var, traces don't work.
var rootConn *grpc.ClientConn
rootConn, rootClient, _ = newClient(
config.RootClientCertFile,
config.RootClientKeyFile,
)
nobodyConn, nobodyClient, _ := newClient(
// If the connection is on created with var, traces don't work.
var nobodyConn *grpc.ClientConn
nobodyConn, nobodyClient, _ = newClient(
config.NobodyClientCertFile,
config.NobodyClientKeyFile,
)
// Server config.
serverTLSConfig, err := config.SetupTLSConfig(config.TLSConfig{
CertFile: config.ServerCertFile,
KeyFile: config.ServerKeyFile,
CAFile: config.CAFile,
ServerAddress: l.Addr().String(),
Server: true,
CertFile: config.ServerCertFile,
KeyFile: config.ServerKeyFile,
CAFile: config.CAFile,
Server: true,
})
require.NoError(t, err)
serverCreds := credentials.NewTLS(serverTLSConfig)
dir, err := ioutil.TempDir("", "server-test")
require.NoError(t, err)
defer os.RemoveAll(dir)
clog, err := log.NewLog(dir, log.Config{})
require.NoError(t, err)
authorizer := auth.New(config.ACLModelFile, config.ACLPolicyFile)
var telemetryExporter *exporter.LogExporter
if *debug {
metricsLogFile, err := ioutil.TempFile("", "metrics-*.log")
require.NoError(t, err)
t.Logf("metrics log file: %s", metricsLogFile.Name())
tracesLogFile, err := ioutil.TempFile("", "traces-*.log")
require.NoError(t, err)
t.Logf("traces log file: %s", tracesLogFile.Name())
telemetryExporter, err = exporter.NewLogExporter(exporter.Options{
MetricsLogFile: metricsLogFile.Name(),
TracesLogFile: tracesLogFile.Name(),
ReportingInterval: time.Second,
})
require.NoError(t, err)
err = telemetryExporter.Start()
require.NoError(t, err)
}
cfg = &Config{
CommitLog: clog,
Authorizer: authorizer,
@ -120,6 +165,12 @@ func setupTest(t *testing.T, fn func(*Config)) (
nobodyConn.Close()
l.Close()
clog.Remove()
if telemetryExporter != nil {
time.Sleep(2000 * time.Millisecond)
telemetryExporter.Stop()
telemetryExporter.Close()
}
}
}