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 }