// Dedup adds a canned filter to the handler which suppresses duplicate // messages. // // When an event is received that contains the same message & fields as a // previous message, the message is not sent on to the next handler. Once a // different message is received, the filter generates a summary message // indicating how many duplicates were suppressed. // // The return value is the handler itself. This is to allow chaining multiple operations together. func (filterHandler *FilterHandler) Dedup() *FilterHandler { var lastLogEvent *event.Event var dups int filterFunc := func(logEvent *event.Event) bool { if lastLogEvent == nil { lastLogEvent = logEvent return true } if lastLogEvent.Message == logEvent.Message && reflect.DeepEqual(lastLogEvent.FlatFields, logEvent.FlatFields) { dups++ lastLogEvent = logEvent return false } if dups > 0 { dupEvent := event.New( lastLogEvent.Id, event.Notice, "duplicates of last log event suppressed", map[string]int{"count": dups}, false, ) filterHandler.nextHandler.Event(dupEvent) } dups = 0 lastLogEvent = logEvent return true } return filterHandler.Filter(filterFunc) }
func TestAirbrakeHandler(t *testing.T) { ah := New(123456, "0123456789abcdef0123456789abcdef", "testing") ah.Context.URL = "http://example.com/airbrake" ah.Context.UserId = "johndoe" ah.Context.UserName = "******" ah.Context.UserEmail = "*****@*****.**" logEvent := event.New(1, event.Warning, "test AirbrakeHandler", map[string]interface{}{"foo": "bar"}, true) err := ah.Event(logEvent) require.NoError(t, err) notice := testAirbrakeServer.notices[len(testAirbrakeServer.notices)-1] nNotifier := notice["notifier"].(map[string]interface{}) assert.Equal(t, notifier.Name, nNotifier["name"]) assert.Equal(t, notifier.Version, nNotifier["version"]) assert.Equal(t, notifier.Url, nNotifier["url"]) _, selfFile, _, _ := runtime.Caller(0) nErrors := notice["errors"].([]interface{}) nError := nErrors[0].(map[string]interface{}) nBacktrace := nError["backtrace"].([]interface{}) nBacktrace0 := nBacktrace[0].(map[string]interface{}) assert.Equal(t, "warning", nError["type"]) assert.Equal(t, "test AirbrakeHandler", nError["message"]) assert.Equal(t, selfFile, nBacktrace0["file"]) assert.NotEmpty(t, nBacktrace0["line"]) assert.Equal(t, "TestAirbrakeHandler", nBacktrace0["function"]) var repoVersion string execCmd := exec.Command("git", "describe", "--dirty", "--tags", "--always") output, err := execCmd.Output() if err == nil { repoVersion = string(bytes.TrimRight(output, "\n")) } nContext := notice["context"].(map[string]interface{}) assert.Equal(t, runtime.GOOS+" "+runtime.GOARCH, nContext["os"]) assert.Equal(t, "go "+runtime.Version(), nContext["language"]) assert.Equal(t, "testing", nContext["environment"]) assert.Equal(t, repoVersion, nContext["version"]) assert.Equal(t, "http://example.com/airbrake", nContext["url"]) assert.Equal(t, "johndoe", nContext["userId"]) assert.Equal(t, "john doe", nContext["userName"]) assert.Equal(t, "*****@*****.**", nContext["userEmail"]) hostname, _ := os.Hostname() nEnvironment := notice["environment"].(map[string]interface{}) assert.Equal(t, fmt.Sprintf("%d", runtime.GOMAXPROCS(0)), nEnvironment["GOMAXPROCS"]) assert.Equal(t, runtime.Version(), nEnvironment["GOVERSION"]) assert.Equal(t, runtime.GOROOT(), nEnvironment["GOROOT"]) assert.Equal(t, hostname, nEnvironment["HOSTNAME"]) nParams := notice["params"].(map[string]interface{}) assert.Equal(t, "bar", nParams["foo"]) }
func TestAppend(t *testing.T) { td, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(td) fp := filepath.Join(td, "TestAppend") wh, err := Append(fp, 0600, "") require.NoError(t, err) f, err := os.Open(fp) require.NoError(t, err) stat, err := f.Stat() require.NoError(t, err) assert.Equal(t, os.FileMode(0600), stat.Mode()) e := event.New(0, event.Info, "TestAppend message 1", nil, false) err = wh.Event(e) require.NoError(t, err) buf := make([]byte, 128) _, err = f.Read(buf) assert.NoError(t, err) assert.Contains(t, string(buf), "TestAppend message 1") // create a new appender and make sure it appends wh, err = Append(fp, 0600, "") require.NoError(t, err) _, err = f.Seek(0, 0) require.NoError(t, err) e = event.New(0, event.Info, "TestAppend message 2", nil, false) err = wh.Event(e) require.NoError(t, err) _, err = f.Read(buf) assert.NoError(t, err) assert.Contains(t, string(buf), "TestAppend message 1") assert.Contains(t, string(buf), "TestAppend message 2") }
func makeEvent(level event.Level) *event.Event { eventCounter++ callerPC, _, _, _ := runtime.Caller(1) callerFunc := runtime.FuncForPC(callerPC) callerName := callerFunc.Name() message := "testing " + callerName + "()" data := map[string]interface{}{"test": callerName} return event.New(eventCounter, level, message, data, false) }
func TestSentryHandler(t *testing.T) { st := &sentryTransport{ user: "******", pass: "******", projectID: "12345", } dsn := fmt.Sprintf("http://%s:%s@%s/%s", "0123456789abcdef0123456789abcdef", "fedcba9876543210fedcba9876543210", "localhost:2", "12345") handler, err := New(dsn) handler.Tag("abcd", "1234") require.NoError(t, err) handler.client.Transport = st logEvent := event.New(1, event.Warning, "test SentryHandler", map[string]interface{}{"error": errors.New("foo"), "foo": "bar", "breakfast": map[string]interface{}{"pop": "tart"}}, true) err = handler.Event(logEvent) require.NoError(t, err) packet := st.packets[len(st.packets)-1] assert.Equal(t, "test SentryHandler: foo", packet.Message) assert.Equal(t, handler.idPrefix+"1", packet.EventID) assert.WithinDuration(t, time.Now(), time.Time(packet.Timestamp), time.Second) assert.Equal(t, raven.WARNING, packet.Level) assert.Equal(t, "sentry.TestSentryHandler", packet.Culprit) assert.Equal(t, "sawmill", packet.Logger) assert.Equal(t, "go", packet.Platform) assert.NotEmpty(t, packet.Release) assert.Equal(t, "bar", packet.Extra["foo"]) assert.Equal(t, "tart", packet.Extra["breakfast.pop"]) assert.Contains(t, packet.Tags, raven.Tag{Key: "abcd", Value: "1234"}) haveStacktrace := false for _, iface := range packet.Interfaces { switch iface := iface.(type) { case *raven.Stacktrace: haveStacktrace = true frame := iface.Frames[len(iface.Frames)-1] assert.Equal(t, "handler/sentry/sentry_test.go", frame.Filename) assert.Equal(t, "TestSentryHandler", frame.Function) assert.Equal(t, "sentry", frame.Module) assert.NotEmpty(t, frame.Lineno) assert.Equal(t, uint8('/'), frame.AbsolutePath[0]) assert.Contains(t, frame.AbsolutePath, "/handler/sentry/sentry_test.go") assert.Equal(t, true, frame.InApp) assert.Equal(t, " handler.client.Transport = st", frame.PreContext[1]) assert.Equal(t, ` logEvent := event.New(1, event.Warning, "test SentryHandler", map[string]interface{}{"error": errors.New("foo"), "foo": "bar", "breakfast": map[string]interface{}{"pop": "tart"}}, true)`, frame.ContextLine) } } assert.True(t, haveStacktrace) handler.Stop() }
func TestStandardStreamsHandler_Event(t *testing.T) { wg := sync.WaitGroup{} pipeOutR, pipeOutW, err := os.Pipe() defer pipeOutW.Close() require.NoError(t, err) defer func(f *os.File) { os.Stdout = f }(os.Stdout) os.Stdout = pipeOutW outbuf := bytes.NewBuffer(nil) wg.Add(1) go func() { io.Copy(outbuf, pipeOutR); wg.Done() }() pipeErrR, pipeErrW, err := os.Pipe() defer pipeErrW.Close() require.NoError(t, err) defer func(f *os.File) { os.Stderr = f }(os.Stderr) os.Stderr = pipeErrW errbuf := bytes.NewBuffer(nil) wg.Add(1) go func() { io.Copy(errbuf, pipeErrR); wg.Done() }() h := NewStandardStreamsHandler() e := event.New(0, event.Info, "TestStandardStreamsHandler_Event info", nil, false) err = h.Event(e) assert.NoError(t, err) e = event.New(0, event.Error, "TestStandardStreamsHandler_Event error", nil, false) err = h.Event(e) assert.NoError(t, err) pipeOutW.Close() pipeErrW.Close() wg.Wait() assert.Contains(t, outbuf.String(), "TestStandardStreamsHandler_Event info") assert.Contains(t, errbuf.String(), "TestStandardStreamsHandler_Event error") }
func TestEvent(t *testing.T) { l, err := newUNIXListener() require.NoError(t, err) defer l.Close() handler, err := New("", l.Addr, DAEMON, "") require.NoError(t, err) logEvent := event.New(1, event.Warning, "testing Event()", map[string]interface{}{"test": "TestEvent"}, false) err = handler.Event(logEvent) require.NoError(t, err) msg := <-l.MsgChan assert.Equal(t, "<28>"+logEvent.Time.Format(time.StampMilli)+" syslog.test["+fmt.Sprintf("%d", os.Getpid())+"]: testing Event() -- test=TestEvent", msg) }
// Event queues a message at the given level. // Additional fields may be provided, which will be recursively copied at the time of the function call, and provided to the destination output handler. // It returns an event Id that can be used with Sync(). func (logger *Logger) Event(level event.Level, message string, fields ...interface{}) uint64 { var eventFields interface{} if len(fields) > 1 { eventFields = fields } else if len(fields) == 1 { eventFields = fields[0] } else if len(fields) == 0 { eventFields = nil } getStack := int32(level) >= atomic.LoadInt32(&logger.stackMinLevel) //TODO do we want to just remove the id param from event.New()? logEvent := event.New(0, level, message, eventFields, getStack) return logger.SendEvent(logEvent) }
func TestEvent(t *testing.T) { sw, err := New(splunkHttpsURL) require.NoError(t, err) logEvent := event.New(1, event.Warning, "testing Event()", map[string]interface{}{"test": "TestEvent"}, false) err = sw.Event(logEvent) assert.NoError(t, err) serverEvent := splunkSvr.events[len(splunkSvr.events)-1] assert.Equal(t, sw.Index, serverEvent.index) assert.Equal(t, sw.Hostname, serverEvent.host) assert.Equal(t, sw.Source, serverEvent.source) assert.Equal(t, sw.SourceType, serverEvent.sourcetype) assert.Contains(t, serverEvent.message, "warning(3)") assert.Contains(t, serverEvent.message, logEvent.Message) assert.Contains(t, serverEvent.message, "test=TestEvent") }