github.com/livekit/protocol@v1.39.3/logger/pionlogger/logger.go (about)

     1  // Copyright 2023 LiveKit, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package pionlogger
    16  
    17  import (
    18  	"maps"
    19  	"slices"
    20  	"strings"
    21  
    22  	"github.com/pion/logging"
    23  
    24  	"github.com/livekit/protocol/logger"
    25  	"github.com/livekit/protocol/utils/options"
    26  	"github.com/livekit/protocol/utils/pointer"
    27  )
    28  
    29  var (
    30  	pionIgnoredPrefixes = map[string]*prefixSet{
    31  		"ice": {
    32  			"pingAllCandidates called with no candidate pairs",
    33  			"failed to send packet: io: read/write on closed pipe",
    34  			"Ignoring remote candidate with tcpType active",
    35  			"discard message from",
    36  			"Failed to discover mDNS candidate",
    37  			"Failed to read from candidate tcp",
    38  			"remote mDNS candidate added, but mDNS is disabled",
    39  		},
    40  		"pc": {
    41  			"Failed to accept RTCP stream is already closed",
    42  			"Failed to accept RTP stream is already closed",
    43  			"Incoming unhandled RTCP ssrc",
    44  		},
    45  		"tcp_mux": {
    46  			"Error reading first packet from",
    47  			"error closing connection",
    48  		},
    49  		"turn": {
    50  			"error when handling datagram",
    51  			"Failed to send ChannelData from allocation",
    52  			"Failed to handle datagram",
    53  		},
    54  	}
    55  )
    56  
    57  type prefixSet []string
    58  
    59  func (s *prefixSet) Match(msg string) bool {
    60  	if s == nil {
    61  		return false
    62  	}
    63  
    64  	for _, prefix := range *s {
    65  		if strings.HasPrefix(msg, prefix) {
    66  			return true
    67  		}
    68  	}
    69  	return false
    70  }
    71  
    72  type PrefixFilter map[string]*prefixSet
    73  
    74  func NewPrefixFilter(prefixes map[string][]string) PrefixFilter {
    75  	p := maps.Clone(pionIgnoredPrefixes)
    76  	for scope, set := range prefixes {
    77  		if prev, ok := p[scope]; ok {
    78  			p[scope] = pointer.To(slices.Concat(*prev, prefixSet(set)))
    79  		} else {
    80  			p[scope] = pointer.To(prefixSet(set))
    81  		}
    82  	}
    83  	return p
    84  }
    85  
    86  type FilterFunc func(msg string) bool
    87  
    88  type Options struct {
    89  	PrefixFilter PrefixFilter
    90  }
    91  
    92  type Option func(o *Options)
    93  
    94  func WithPrefixFilter(f PrefixFilter) Option {
    95  	return func(o *Options) {
    96  		o.PrefixFilter = f
    97  	}
    98  }
    99  
   100  func NewLoggerFactory(l logger.Logger, opts ...Option) logging.LoggerFactory {
   101  	o := Options{
   102  		PrefixFilter: pionIgnoredPrefixes,
   103  	}
   104  	options.Apply(&o, opts)
   105  
   106  	if zl, ok := l.(logger.ZapLogger); ok {
   107  		return &zapLoggerFactory{zl, o}
   108  	}
   109  	return &loggerFactory{l, o}
   110  }
   111  
   112  // zapLoggerFactory implements logging.LoggerFactory interface for zap loggers
   113  type zapLoggerFactory struct {
   114  	logger  logger.ZapLogger
   115  	options Options
   116  }
   117  
   118  func (f *zapLoggerFactory) NewLogger(scope string) logging.LeveledLogger {
   119  	return &zapLogAdapter{
   120  		logger:          f.logger,
   121  		level:           f.logger.ComponentLeveler().ComponentLevel(formatComponent(scope)),
   122  		scope:           scope,
   123  		ignoredPrefixes: f.options.PrefixFilter[scope],
   124  	}
   125  }
   126  
   127  // loggerFactory implements logging.LoggerFactory interface for generic loggers
   128  type loggerFactory struct {
   129  	logger  logger.Logger
   130  	options Options
   131  }
   132  
   133  func (f *loggerFactory) NewLogger(scope string) logging.LeveledLogger {
   134  	return &logAdapter{
   135  		logger:          f.logger.WithComponent(formatComponent(scope)).WithCallDepth(1),
   136  		ignoredPrefixes: f.options.PrefixFilter[scope],
   137  	}
   138  }
   139  
   140  func formatComponent(scope string) string {
   141  	return "pion." + scope
   142  }