2022-04-03 04:07:16 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Copyright 2018 gRPC authors.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Package binarylog implementation binary logging as defined in
|
|
|
|
// https://github.com/grpc/proposal/blob/master/A16-binary-logging.md.
|
|
|
|
package binarylog
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"google.golang.org/grpc/grpclog"
|
2022-08-06 14:21:18 +00:00
|
|
|
"google.golang.org/grpc/internal/grpcutil"
|
2022-04-03 04:07:16 +00:00
|
|
|
)
|
|
|
|
|
2023-07-03 20:21:30 +00:00
|
|
|
var grpclogLogger = grpclog.Component("binarylog")
|
|
|
|
|
|
|
|
// Logger specifies MethodLoggers for method names with a Log call that
|
|
|
|
// takes a context.
|
|
|
|
//
|
|
|
|
// This is used in the 1.0 release of gcp/observability, and thus must not be
|
|
|
|
// deleted or changed.
|
2022-04-03 04:07:16 +00:00
|
|
|
type Logger interface {
|
2022-08-06 14:21:18 +00:00
|
|
|
GetMethodLogger(methodName string) MethodLogger
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// binLogger is the global binary logger for the binary. One of this should be
|
|
|
|
// built at init time from the configuration (environment variable or flags).
|
|
|
|
//
|
2022-12-24 16:57:19 +00:00
|
|
|
// It is used to get a MethodLogger for each individual method.
|
2022-04-03 04:07:16 +00:00
|
|
|
var binLogger Logger
|
|
|
|
|
2022-08-06 14:21:18 +00:00
|
|
|
// SetLogger sets the binary logger.
|
2022-04-03 04:07:16 +00:00
|
|
|
//
|
|
|
|
// Only call this at init time.
|
|
|
|
func SetLogger(l Logger) {
|
|
|
|
binLogger = l
|
|
|
|
}
|
|
|
|
|
2022-08-06 14:21:18 +00:00
|
|
|
// GetLogger gets the binary logger.
|
|
|
|
//
|
|
|
|
// Only call this at init time.
|
|
|
|
func GetLogger() Logger {
|
|
|
|
return binLogger
|
|
|
|
}
|
|
|
|
|
2022-12-24 16:57:19 +00:00
|
|
|
// GetMethodLogger returns the MethodLogger for the given methodName.
|
2022-04-03 04:07:16 +00:00
|
|
|
//
|
|
|
|
// methodName should be in the format of "/service/method".
|
|
|
|
//
|
2022-12-24 16:57:19 +00:00
|
|
|
// Each MethodLogger returned by this method is a new instance. This is to
|
2022-04-03 04:07:16 +00:00
|
|
|
// generate sequence id within the call.
|
2022-08-06 14:21:18 +00:00
|
|
|
func GetMethodLogger(methodName string) MethodLogger {
|
2022-04-03 04:07:16 +00:00
|
|
|
if binLogger == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
return binLogger.GetMethodLogger(methodName)
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
const envStr = "GRPC_BINARY_LOG_FILTER"
|
|
|
|
configStr := os.Getenv(envStr)
|
|
|
|
binLogger = NewLoggerFromConfigString(configStr)
|
|
|
|
}
|
|
|
|
|
2022-08-06 14:21:18 +00:00
|
|
|
// MethodLoggerConfig contains the setting for logging behavior of a method
|
|
|
|
// logger. Currently, it contains the max length of header and message.
|
|
|
|
type MethodLoggerConfig struct {
|
2022-04-03 04:07:16 +00:00
|
|
|
// Max length of header and message.
|
2022-08-06 14:21:18 +00:00
|
|
|
Header, Message uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
// LoggerConfig contains the config for loggers to create method loggers.
|
|
|
|
type LoggerConfig struct {
|
|
|
|
All *MethodLoggerConfig
|
|
|
|
Services map[string]*MethodLoggerConfig
|
|
|
|
Methods map[string]*MethodLoggerConfig
|
|
|
|
|
|
|
|
Blacklist map[string]struct{}
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type logger struct {
|
2022-08-06 14:21:18 +00:00
|
|
|
config LoggerConfig
|
|
|
|
}
|
2022-04-03 04:07:16 +00:00
|
|
|
|
2022-08-06 14:21:18 +00:00
|
|
|
// NewLoggerFromConfig builds a logger with the given LoggerConfig.
|
|
|
|
func NewLoggerFromConfig(config LoggerConfig) Logger {
|
|
|
|
return &logger{config: config}
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// newEmptyLogger creates an empty logger. The map fields need to be filled in
|
|
|
|
// using the set* functions.
|
|
|
|
func newEmptyLogger() *logger {
|
|
|
|
return &logger{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set method logger for "*".
|
2022-08-06 14:21:18 +00:00
|
|
|
func (l *logger) setDefaultMethodLogger(ml *MethodLoggerConfig) error {
|
|
|
|
if l.config.All != nil {
|
2022-04-03 04:07:16 +00:00
|
|
|
return fmt.Errorf("conflicting global rules found")
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
l.config.All = ml
|
2022-04-03 04:07:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set method logger for "service/*".
|
|
|
|
//
|
2022-12-24 16:57:19 +00:00
|
|
|
// New MethodLogger with same service overrides the old one.
|
2022-08-06 14:21:18 +00:00
|
|
|
func (l *logger) setServiceMethodLogger(service string, ml *MethodLoggerConfig) error {
|
|
|
|
if _, ok := l.config.Services[service]; ok {
|
2022-04-03 04:07:16 +00:00
|
|
|
return fmt.Errorf("conflicting service rules for service %v found", service)
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if l.config.Services == nil {
|
|
|
|
l.config.Services = make(map[string]*MethodLoggerConfig)
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
l.config.Services[service] = ml
|
2022-04-03 04:07:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set method logger for "service/method".
|
|
|
|
//
|
2022-12-24 16:57:19 +00:00
|
|
|
// New MethodLogger with same method overrides the old one.
|
2022-08-06 14:21:18 +00:00
|
|
|
func (l *logger) setMethodMethodLogger(method string, ml *MethodLoggerConfig) error {
|
|
|
|
if _, ok := l.config.Blacklist[method]; ok {
|
2022-04-03 04:07:16 +00:00
|
|
|
return fmt.Errorf("conflicting blacklist rules for method %v found", method)
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if _, ok := l.config.Methods[method]; ok {
|
2022-04-03 04:07:16 +00:00
|
|
|
return fmt.Errorf("conflicting method rules for method %v found", method)
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if l.config.Methods == nil {
|
|
|
|
l.config.Methods = make(map[string]*MethodLoggerConfig)
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
l.config.Methods[method] = ml
|
2022-04-03 04:07:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set blacklist method for "-service/method".
|
|
|
|
func (l *logger) setBlacklist(method string) error {
|
2022-08-06 14:21:18 +00:00
|
|
|
if _, ok := l.config.Blacklist[method]; ok {
|
2022-04-03 04:07:16 +00:00
|
|
|
return fmt.Errorf("conflicting blacklist rules for method %v found", method)
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if _, ok := l.config.Methods[method]; ok {
|
2022-04-03 04:07:16 +00:00
|
|
|
return fmt.Errorf("conflicting method rules for method %v found", method)
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if l.config.Blacklist == nil {
|
|
|
|
l.config.Blacklist = make(map[string]struct{})
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
l.config.Blacklist[method] = struct{}{}
|
2022-04-03 04:07:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-24 16:57:19 +00:00
|
|
|
// getMethodLogger returns the MethodLogger for the given methodName.
|
2022-04-03 04:07:16 +00:00
|
|
|
//
|
|
|
|
// methodName should be in the format of "/service/method".
|
|
|
|
//
|
2022-12-24 16:57:19 +00:00
|
|
|
// Each MethodLogger returned by this method is a new instance. This is to
|
2022-04-03 04:07:16 +00:00
|
|
|
// generate sequence id within the call.
|
2022-08-06 14:21:18 +00:00
|
|
|
func (l *logger) GetMethodLogger(methodName string) MethodLogger {
|
|
|
|
s, m, err := grpcutil.ParseMethod(methodName)
|
2022-04-03 04:07:16 +00:00
|
|
|
if err != nil {
|
2022-08-06 14:21:18 +00:00
|
|
|
grpclogLogger.Infof("binarylogging: failed to parse %q: %v", methodName, err)
|
2022-04-03 04:07:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if ml, ok := l.config.Methods[s+"/"+m]; ok {
|
2022-12-24 16:57:19 +00:00
|
|
|
return NewTruncatingMethodLogger(ml.Header, ml.Message)
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if _, ok := l.config.Blacklist[s+"/"+m]; ok {
|
2022-04-03 04:07:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if ml, ok := l.config.Services[s]; ok {
|
2022-12-24 16:57:19 +00:00
|
|
|
return NewTruncatingMethodLogger(ml.Header, ml.Message)
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|
2022-08-06 14:21:18 +00:00
|
|
|
if l.config.All == nil {
|
2022-04-03 04:07:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
2022-12-24 16:57:19 +00:00
|
|
|
return NewTruncatingMethodLogger(l.config.All.Header, l.config.All.Message)
|
2022-04-03 04:07:16 +00:00
|
|
|
}
|