github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/metrics/logging_hook.go (about)

     1  // Copyright 2018 Authors of Cilium
     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 metrics
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  
    21  	"github.com/cilium/cilium/pkg/components"
    22  	"github.com/cilium/cilium/pkg/logging/logfields"
    23  
    24  	"github.com/sirupsen/logrus"
    25  )
    26  
    27  // LoggingHook is a hook for logrus which counts error and warning messages as a
    28  // Prometheus metric.
    29  type LoggingHook struct {
    30  	metric CounterVec
    31  }
    32  
    33  // NewLoggingHook returns a new instance of LoggingHook for the given Cilium
    34  // component.
    35  func NewLoggingHook(component string) *LoggingHook {
    36  	// NOTE(mrostecki): For now errors and warning metric exists only for Cilium
    37  	// daemon, but support of Prometheus metrics in some other components (i.e.
    38  	// cilium-health - GH-4268) is planned.
    39  
    40  	// Pick a metric for the component.
    41  	var metric CounterVec
    42  	switch component {
    43  	case components.CiliumAgentName:
    44  		metric = ErrorsWarnings
    45  	default:
    46  		panic(fmt.Sprintf("component %s is unsupported by LoggingHook", component))
    47  	}
    48  
    49  	return &LoggingHook{metric: metric}
    50  }
    51  
    52  // Levels returns the list of logging levels on which the hook is triggered.
    53  func (h *LoggingHook) Levels() []logrus.Level {
    54  	return []logrus.Level{
    55  		logrus.ErrorLevel,
    56  		logrus.WarnLevel,
    57  	}
    58  }
    59  
    60  // Fire is the main method which is called every time when logger has an error
    61  // or warning message.
    62  func (h *LoggingHook) Fire(entry *logrus.Entry) error {
    63  	// Get information about subsystem from logging entry field.
    64  	iSubsystem, ok := entry.Data[logfields.LogSubsys]
    65  	if !ok {
    66  		serializedEntry, err := entry.String()
    67  		if err != nil {
    68  			return fmt.Errorf("log entry cannot be serialized and doesn't contain 'subsys' field")
    69  		}
    70  		return fmt.Errorf("log entry doesn't contain 'subsys' field: %s", serializedEntry)
    71  	}
    72  	subsystem, ok := iSubsystem.(string)
    73  	if !ok {
    74  		return fmt.Errorf("type of the 'subsystem' log entry field is not string but %s", reflect.TypeOf(iSubsystem))
    75  	}
    76  
    77  	// Increment the metric.
    78  	h.metric.WithLabelValues(entry.Level.String(), subsystem).Inc()
    79  
    80  	return nil
    81  }