github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/log/sentryHook.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"github.com/getsentry/sentry-go"
     8  	"github.com/sirupsen/logrus"
     9  )
    10  
    11  // conversion from logrus log level to sentry log level
    12  var (
    13  	levelMap = map[logrus.Level]sentry.Level{
    14  		logrus.TraceLevel: sentry.LevelDebug,
    15  		logrus.DebugLevel: sentry.LevelDebug,
    16  		logrus.InfoLevel:  sentry.LevelInfo,
    17  		logrus.WarnLevel:  sentry.LevelWarning,
    18  		logrus.ErrorLevel: sentry.LevelError,
    19  		logrus.FatalLevel: sentry.LevelFatal,
    20  		logrus.PanicLevel: sentry.LevelFatal,
    21  	}
    22  )
    23  
    24  // SentryHook provides a logrus hook which enables error logging to sentry platform.
    25  // This is helpful in order to provide better monitoring and alerting on errors
    26  // as well as the given error details can help to find the root cause of bugs.
    27  type SentryHook struct {
    28  	levels        []logrus.Level
    29  	Hub           *sentry.Hub
    30  	tags          map[string]string
    31  	Event         *sentry.Event
    32  	correlationID string
    33  }
    34  
    35  // NewSentryHook initializes sentry sdk with dsn and creates new hook
    36  func NewSentryHook(sentryDsn, correlationID string) SentryHook {
    37  	Entry().Debugf("Initializing Sentry with DSN %v", sentryDsn)
    38  	if err := sentry.Init(sentry.ClientOptions{
    39  		Dsn:              sentryDsn,
    40  		AttachStacktrace: true,
    41  	}); err != nil {
    42  		Entry().Warnf("cannot initialize sentry: %v", err)
    43  	}
    44  	h := SentryHook{
    45  		levels:        []logrus.Level{logrus.PanicLevel, logrus.FatalLevel},
    46  		Hub:           sentry.CurrentHub(),
    47  		tags:          make(map[string]string),
    48  		Event:         sentry.NewEvent(),
    49  		correlationID: correlationID,
    50  	}
    51  	return h
    52  }
    53  
    54  // Levels returns the supported log level of the hook.
    55  func (sentryHook *SentryHook) Levels() []logrus.Level {
    56  	return sentryHook.levels
    57  }
    58  
    59  // Fire creates a new event from the error and sends it to sentry
    60  func (sentryHook *SentryHook) Fire(entry *logrus.Entry) error {
    61  	sentryHook.Event.Level = levelMap[entry.Level]
    62  	sentryHook.Event.Message = entry.Message
    63  	errValue := ""
    64  	sentryHook.tags["correlationId"] = sentryHook.correlationID
    65  	sentryHook.tags["category"] = GetErrorCategory().String()
    66  	for k, v := range entry.Data {
    67  		if k == "stepName" || k == "category" {
    68  			sentryHook.tags[k] = fmt.Sprint(v)
    69  		}
    70  		if k == "error" {
    71  			errValue = fmt.Sprint(v)
    72  		}
    73  		sentryHook.Event.Extra[k] = v
    74  	}
    75  	sentryHook.Hub.Scope().SetTags(sentryHook.tags)
    76  
    77  	exception := sentry.Exception{
    78  		Type:  entry.Message,
    79  		Value: errValue,
    80  	}
    81  
    82  	// if error type found overwrite exception value and add stacktrace
    83  	err, ok := entry.Data[logrus.ErrorKey].(error)
    84  	if ok {
    85  		exception.Value = err.Error()
    86  		sentryHook.Event.Message = reflect.TypeOf(err).String()
    87  		if sentryHook.Hub.Client().Options().AttachStacktrace {
    88  			exception.Stacktrace = sentry.ExtractStacktrace(err)
    89  		}
    90  
    91  	}
    92  	sentryHook.Event.Exception = []sentry.Exception{exception}
    93  
    94  	sentryHook.Hub.CaptureEvent(sentryHook.Event)
    95  	return nil
    96  }