blob: 755fdebc1b15aaa075397e6b59a22e303fc41a01 [file] [log] [blame]
William Kurkianea869482019-04-09 15:16:11 -04001/*
2 *
3 * Copyright 2018 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19// Package binarylog implementation binary logging as defined in
20// https://github.com/grpc/proposal/blob/master/A16-binary-logging.md.
21package binarylog
22
23import (
24 "fmt"
25 "os"
26
27 "google.golang.org/grpc/grpclog"
Abhay Kumara61c5222025-11-10 07:32:50 +000028 "google.golang.org/grpc/internal/grpcutil"
William Kurkianea869482019-04-09 15:16:11 -040029)
30
Abhay Kumara61c5222025-11-10 07:32:50 +000031var grpclogLogger = grpclog.Component("binarylog")
32
33// Logger specifies MethodLoggers for method names with a Log call that
34// takes a context.
35//
36// This is used in the 1.0 release of gcp/observability, and thus must not be
37// deleted or changed.
William Kurkianea869482019-04-09 15:16:11 -040038type Logger interface {
Abhay Kumara61c5222025-11-10 07:32:50 +000039 GetMethodLogger(methodName string) MethodLogger
William Kurkianea869482019-04-09 15:16:11 -040040}
41
42// binLogger is the global binary logger for the binary. One of this should be
Devmalya Pauldd23a992019-11-14 07:06:31 +000043// built at init time from the configuration (environment variable or flags).
William Kurkianea869482019-04-09 15:16:11 -040044//
Abhay Kumara61c5222025-11-10 07:32:50 +000045// It is used to get a MethodLogger for each individual method.
William Kurkianea869482019-04-09 15:16:11 -040046var binLogger Logger
47
Abhay Kumara61c5222025-11-10 07:32:50 +000048// SetLogger sets the binary logger.
William Kurkianea869482019-04-09 15:16:11 -040049//
50// Only call this at init time.
51func SetLogger(l Logger) {
52 binLogger = l
53}
54
Abhay Kumara61c5222025-11-10 07:32:50 +000055// GetLogger gets the binary logger.
56//
57// Only call this at init time.
58func GetLogger() Logger {
59 return binLogger
60}
61
62// GetMethodLogger returns the MethodLogger for the given methodName.
William Kurkianea869482019-04-09 15:16:11 -040063//
64// methodName should be in the format of "/service/method".
65//
Abhay Kumara61c5222025-11-10 07:32:50 +000066// Each MethodLogger returned by this method is a new instance. This is to
William Kurkianea869482019-04-09 15:16:11 -040067// generate sequence id within the call.
Abhay Kumara61c5222025-11-10 07:32:50 +000068func GetMethodLogger(methodName string) MethodLogger {
William Kurkianea869482019-04-09 15:16:11 -040069 if binLogger == nil {
70 return nil
71 }
Abhay Kumara61c5222025-11-10 07:32:50 +000072 return binLogger.GetMethodLogger(methodName)
William Kurkianea869482019-04-09 15:16:11 -040073}
74
75func init() {
76 const envStr = "GRPC_BINARY_LOG_FILTER"
77 configStr := os.Getenv(envStr)
78 binLogger = NewLoggerFromConfigString(configStr)
79}
80
Abhay Kumara61c5222025-11-10 07:32:50 +000081// MethodLoggerConfig contains the setting for logging behavior of a method
82// logger. Currently, it contains the max length of header and message.
83type MethodLoggerConfig struct {
William Kurkianea869482019-04-09 15:16:11 -040084 // Max length of header and message.
Abhay Kumara61c5222025-11-10 07:32:50 +000085 Header, Message uint64
86}
87
88// LoggerConfig contains the config for loggers to create method loggers.
89type LoggerConfig struct {
90 All *MethodLoggerConfig
91 Services map[string]*MethodLoggerConfig
92 Methods map[string]*MethodLoggerConfig
93
94 Blacklist map[string]struct{}
William Kurkianea869482019-04-09 15:16:11 -040095}
96
97type logger struct {
Abhay Kumara61c5222025-11-10 07:32:50 +000098 config LoggerConfig
99}
William Kurkianea869482019-04-09 15:16:11 -0400100
Abhay Kumara61c5222025-11-10 07:32:50 +0000101// NewLoggerFromConfig builds a logger with the given LoggerConfig.
102func NewLoggerFromConfig(config LoggerConfig) Logger {
103 return &logger{config: config}
William Kurkianea869482019-04-09 15:16:11 -0400104}
105
106// newEmptyLogger creates an empty logger. The map fields need to be filled in
107// using the set* functions.
108func newEmptyLogger() *logger {
109 return &logger{}
110}
111
112// Set method logger for "*".
Abhay Kumara61c5222025-11-10 07:32:50 +0000113func (l *logger) setDefaultMethodLogger(ml *MethodLoggerConfig) error {
114 if l.config.All != nil {
William Kurkianea869482019-04-09 15:16:11 -0400115 return fmt.Errorf("conflicting global rules found")
116 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000117 l.config.All = ml
William Kurkianea869482019-04-09 15:16:11 -0400118 return nil
119}
120
121// Set method logger for "service/*".
122//
Abhay Kumara61c5222025-11-10 07:32:50 +0000123// New MethodLogger with same service overrides the old one.
124func (l *logger) setServiceMethodLogger(service string, ml *MethodLoggerConfig) error {
125 if _, ok := l.config.Services[service]; ok {
126 return fmt.Errorf("conflicting service rules for service %v found", service)
William Kurkianea869482019-04-09 15:16:11 -0400127 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000128 if l.config.Services == nil {
129 l.config.Services = make(map[string]*MethodLoggerConfig)
William Kurkianea869482019-04-09 15:16:11 -0400130 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000131 l.config.Services[service] = ml
William Kurkianea869482019-04-09 15:16:11 -0400132 return nil
133}
134
135// Set method logger for "service/method".
136//
Abhay Kumara61c5222025-11-10 07:32:50 +0000137// New MethodLogger with same method overrides the old one.
138func (l *logger) setMethodMethodLogger(method string, ml *MethodLoggerConfig) error {
139 if _, ok := l.config.Blacklist[method]; ok {
140 return fmt.Errorf("conflicting blacklist rules for method %v found", method)
William Kurkianea869482019-04-09 15:16:11 -0400141 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000142 if _, ok := l.config.Methods[method]; ok {
143 return fmt.Errorf("conflicting method rules for method %v found", method)
William Kurkianea869482019-04-09 15:16:11 -0400144 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000145 if l.config.Methods == nil {
146 l.config.Methods = make(map[string]*MethodLoggerConfig)
William Kurkianea869482019-04-09 15:16:11 -0400147 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000148 l.config.Methods[method] = ml
William Kurkianea869482019-04-09 15:16:11 -0400149 return nil
150}
151
152// Set blacklist method for "-service/method".
153func (l *logger) setBlacklist(method string) error {
Abhay Kumara61c5222025-11-10 07:32:50 +0000154 if _, ok := l.config.Blacklist[method]; ok {
155 return fmt.Errorf("conflicting blacklist rules for method %v found", method)
William Kurkianea869482019-04-09 15:16:11 -0400156 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000157 if _, ok := l.config.Methods[method]; ok {
158 return fmt.Errorf("conflicting method rules for method %v found", method)
William Kurkianea869482019-04-09 15:16:11 -0400159 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000160 if l.config.Blacklist == nil {
161 l.config.Blacklist = make(map[string]struct{})
William Kurkianea869482019-04-09 15:16:11 -0400162 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000163 l.config.Blacklist[method] = struct{}{}
William Kurkianea869482019-04-09 15:16:11 -0400164 return nil
165}
166
Abhay Kumara61c5222025-11-10 07:32:50 +0000167// getMethodLogger returns the MethodLogger for the given methodName.
William Kurkianea869482019-04-09 15:16:11 -0400168//
169// methodName should be in the format of "/service/method".
170//
Abhay Kumara61c5222025-11-10 07:32:50 +0000171// Each MethodLogger returned by this method is a new instance. This is to
William Kurkianea869482019-04-09 15:16:11 -0400172// generate sequence id within the call.
Abhay Kumara61c5222025-11-10 07:32:50 +0000173func (l *logger) GetMethodLogger(methodName string) MethodLogger {
174 s, m, err := grpcutil.ParseMethod(methodName)
William Kurkianea869482019-04-09 15:16:11 -0400175 if err != nil {
Abhay Kumara61c5222025-11-10 07:32:50 +0000176 grpclogLogger.Infof("binarylogging: failed to parse %q: %v", methodName, err)
William Kurkianea869482019-04-09 15:16:11 -0400177 return nil
178 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000179 if ml, ok := l.config.Methods[s+"/"+m]; ok {
180 return NewTruncatingMethodLogger(ml.Header, ml.Message)
William Kurkianea869482019-04-09 15:16:11 -0400181 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000182 if _, ok := l.config.Blacklist[s+"/"+m]; ok {
William Kurkianea869482019-04-09 15:16:11 -0400183 return nil
184 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000185 if ml, ok := l.config.Services[s]; ok {
186 return NewTruncatingMethodLogger(ml.Header, ml.Message)
William Kurkianea869482019-04-09 15:16:11 -0400187 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000188 if l.config.All == nil {
William Kurkianea869482019-04-09 15:16:11 -0400189 return nil
190 }
Abhay Kumara61c5222025-11-10 07:32:50 +0000191 return NewTruncatingMethodLogger(l.config.All.Header, l.config.All.Message)
William Kurkianea869482019-04-09 15:16:11 -0400192}