Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add honeybadger_events appender #280

Merged
merged 3 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [4.16.0]

- Add appender for Honeybadger Insights using the events API
- Add support for Ruby 3.3.
- Allow SyncProcessor to be called from appenders.
- Fix incorrect metrics usage examples in documentation.
Expand All @@ -24,7 +25,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [4.13.0]

- Replace `autoload` with `require` for most requires since Ruby does not allow a require
during a signal trap for the extreme use case where the logger is called from the signal
during a signal trap for the extreme use case where the logger is called from the signal
trap before the application has made any logging calls.

- Move `newrelic_rpm.rb` mock to the `test/mocks` directory
Expand Down Expand Up @@ -58,7 +59,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Updated RuboCop's target version to Ruby 2.7.5.
- Updated minimum Ruby version to 2.7.5 as earlier versions are
end-of-life.
- Add mutexes to `SemanticLogger.sync!` in case some users are still using it in a
- Add mutexes to `SemanticLogger.sync!` in case some users are still using it in a
multi-threaded environment.

## [4.11.0]
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Semantic Logger
[![Gem Version](https://img.shields.io/gem/v/semantic_logger.svg)](https://rubygems.org/gems/semantic_logger) [![Build Status](https://github.com/reidmorrison/semantic_logger/workflows/build/badge.svg)](https://github.com/reidmorrison/semantic_logger/actions?query=workflow%3Abuild) [![Downloads](https://img.shields.io/gem/dt/semantic_logger.svg)](https://rubygems.org/gems/semantic_logger) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg)

Semantic Logger is a feature rich logging framework, and replacement for existing Ruby & Rails loggers.
Semantic Logger is a feature rich logging framework, and replacement for existing Ruby & Rails loggers.

* https://logger.rocketjob.io/

Expand All @@ -21,7 +21,7 @@ Logging to the following destinations are all supported "out-of-the-box":
* NewRelic
* Splunk
* MongoDB
* Honeybadger
* Honeybadger (exceptions and events)
* Sentry (both with legacy `sentry-raven` and modern `sentry-ruby` gem)
* HTTP
* TCP
Expand Down Expand Up @@ -54,6 +54,8 @@ The following gems are only required when their corresponding appenders are bein
and are therefore not automatically included by this gem:
- Bugsnag Appender: gem 'bugsnag'
- MongoDB Appender: gem 'mongo' 1.9.2 or above
- Honeybadger Appender: gem 'honeybadger'
- HoneybadgerInsights Appender: gem 'honeybadger'
- NewRelic Appender: gem 'newrelic_rpm'
- NewRelicLogs Appender: gem 'newrelic_rpm'
- Syslog Appender: gem 'syslog_protocol' 0.9.2 or above
Expand Down Expand Up @@ -129,16 +131,16 @@ logger.debug payload: {foo: 'foo', bar: 'bar'}
Similarly, for measure blocks:

~~~ruby
logger.measure_info('How long is the sleep', foo: 'foo', bar: 'bar') { sleep 1 }
logger.measure_info('How long is the sleep', foo: 'foo', bar: 'bar') { sleep 1 }
~~~

Must be replaced with the following in v4:

~~~ruby
logger.measure_info('How long is the sleep', payload: {foo: 'foo', bar: 'bar'}) { sleep 1 }
logger.measure_info('How long is the sleep', payload: {foo: 'foo', bar: 'bar'}) { sleep 1 }
~~~

The common log call has not changed, and the payload is still logged directly:
The common log call has not changed, and the payload is still logged directly:

~~~ruby
logger.debug('log this', foo: 'foo', bar: 'bar')
Expand Down
47 changes: 24 additions & 23 deletions lib/semantic_logger/appender.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
module SemanticLogger
module Appender
# @formatter:off
autoload :Async, "semantic_logger/appender/async"
autoload :AsyncBatch, "semantic_logger/appender/async_batch"
autoload :Bugsnag, "semantic_logger/appender/bugsnag"
autoload :Elasticsearch, "semantic_logger/appender/elasticsearch"
autoload :ElasticsearchHttp, "semantic_logger/appender/elasticsearch_http"
autoload :File, "semantic_logger/appender/file"
autoload :Graylog, "semantic_logger/appender/graylog"
autoload :Honeybadger, "semantic_logger/appender/honeybadger"
autoload :IO, "semantic_logger/appender/io"
autoload :Kafka, "semantic_logger/appender/kafka"
autoload :Sentry, "semantic_logger/appender/sentry"
autoload :Http, "semantic_logger/appender/http"
autoload :MongoDB, "semantic_logger/appender/mongodb"
autoload :NewRelic, "semantic_logger/appender/new_relic"
autoload :NewRelicLogs, "semantic_logger/appender/new_relic_logs"
autoload :Rabbitmq, "semantic_logger/appender/rabbitmq"
autoload :Splunk, "semantic_logger/appender/splunk"
autoload :SplunkHttp, "semantic_logger/appender/splunk_http"
autoload :Syslog, "semantic_logger/appender/syslog"
autoload :Tcp, "semantic_logger/appender/tcp"
autoload :Udp, "semantic_logger/appender/udp"
autoload :Wrapper, "semantic_logger/appender/wrapper"
autoload :SentryRuby, "semantic_logger/appender/sentry_ruby"
autoload :Async, "semantic_logger/appender/async"
autoload :AsyncBatch, "semantic_logger/appender/async_batch"
autoload :Bugsnag, "semantic_logger/appender/bugsnag"
autoload :Elasticsearch, "semantic_logger/appender/elasticsearch"
autoload :ElasticsearchHttp, "semantic_logger/appender/elasticsearch_http"
autoload :File, "semantic_logger/appender/file"
autoload :Graylog, "semantic_logger/appender/graylog"
autoload :Honeybadger, "semantic_logger/appender/honeybadger"
autoload :HoneybadgerInsights, "semantic_logger/appender/honeybadger_insights"
autoload :IO, "semantic_logger/appender/io"
autoload :Kafka, "semantic_logger/appender/kafka"
autoload :Sentry, "semantic_logger/appender/sentry"
autoload :Http, "semantic_logger/appender/http"
autoload :MongoDB, "semantic_logger/appender/mongodb"
autoload :NewRelic, "semantic_logger/appender/new_relic"
autoload :NewRelicLogs, "semantic_logger/appender/new_relic_logs"
autoload :Rabbitmq, "semantic_logger/appender/rabbitmq"
autoload :Splunk, "semantic_logger/appender/splunk"
autoload :SplunkHttp, "semantic_logger/appender/splunk_http"
autoload :Syslog, "semantic_logger/appender/syslog"
autoload :Tcp, "semantic_logger/appender/tcp"
autoload :Udp, "semantic_logger/appender/udp"
autoload :Wrapper, "semantic_logger/appender/wrapper"
autoload :SentryRuby, "semantic_logger/appender/sentry_ruby"
# @formatter:on

# Returns [SemanticLogger::Subscriber] appender for the supplied options
Expand Down
61 changes: 61 additions & 0 deletions lib/semantic_logger/appender/honeybadger_insights.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
begin
require "honeybadger"
rescue LoadError
raise LoadError, 'Gem honeybadger is required for logging purposes. Please add the gem "honeybadger" to your Gemfile.'
end

# Send log messages to honeybadger events/insights API
#
# Example:
# SemanticLogger.add_appender(appender: :honeybadger_insights)
#
module SemanticLogger
module Appender
class HoneybadgerInsights < SemanticLogger::Subscriber
# Honeybadger Appender
#
# Parameters
# level: [:trace | :debug | :info | :warn | :error | :fatal]
# Override the log level for this appender.
# Default: :error
#
# formatter: [Object|Proc|Symbol|Hash]
# An instance of a class that implements #call, or a Proc to be used to format
# the output from this appender
# Default: Use the built-in formatter (See: #call)
#
# filter: [Regexp|Proc]
# RegExp: Only include log messages where the class name matches the supplied.
# regular expression. All other messages will be ignored.
# Proc: Only include log messages where the supplied Proc returns true
# The Proc must return true or false.
#
# host: [String]
# Name of this host to appear in log messages.
# Default: SemanticLogger.host
#
# application: [String]
# Name of this application to appear in log messages.
# Default: SemanticLogger.application
def initialize(level: :info, **args, &block)
super(level: level, **args, &block)
end

# Send log to honeybadger events API
def log(log)
event = formatter.call(log, self)

::Honeybadger.event(event)

true
end

private

# Use Raw Formatter by default
def default_formatter
SemanticLogger::Formatters::Raw.new(time_key: :ts, time_format: :rfc_3339)
end
end
end
end
53 changes: 53 additions & 0 deletions test/appender/honeybadger_insights_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
require_relative "../test_helper"

# Unit Test for SemanticLogger::Appender::HoneybadgerInsights
module Appender
class HoneybadgerInsightsTest < Minitest::Test
describe SemanticLogger::Appender::HoneybadgerInsights do
before do
@appender = SemanticLogger::Appender::HoneybadgerInsights.new(level: :trace)
@message = "AppenderHoneybadgerInsightsTest log message"
end

SemanticLogger::Levels::LEVELS.each do |level|
it "sends :#{level} notifications to Honeybadger" do
hash = nil
Honeybadger.stub(:event, ->(h) { hash = h }) do
@appender.send(level, @message)
end

refute_nil hash[:ts]
assert_equal @message, hash[:message]
assert_equal level, hash[:level]
end
end

it "send notification to Honeybadger with custom attributes" do
hash = nil
Honeybadger.stub(:event, ->(h) { hash = h }) do
SemanticLogger.tagged("test") do
SemanticLogger.named_tagged(key1: 1, key2: "a") do
@appender.measure_error(message: @message, payload: {key3: 4}) do
sleep 0.001
end
end
end
end

refute_nil hash[:ts]
assert_equal @message, hash[:message]
assert_equal :error, hash[:level]

assert_equal ["test"], hash[:tags]

assert_equal 1, hash[:named_tags][:key1]
assert_equal "a", hash[:named_tags][:key2]

refute_nil hash[:duration]
refute_nil hash[:duration_ms]

assert_equal 4, hash[:payload][:key3]
end
end
end
end
Loading