class SemanticLogger::Appender::SentryRuby

def default_formatter

Use Raw Formatter by default
def default_formatter
  SemanticLogger::Formatters::Raw.new
end

def extract_tags!(context)


Finally, the tag names are limited to 32 characters and the tag values to 256.

joined with a comma.
be used as a "tag" named tag. If such a tag already exists, it is also
Unnamed tags will be stringified and joined with a comma. Then they will
Named tags will be stringified (both key and value).

Extract tags.
def extract_tags!(context)
  named_tags = context.delete(:named_tags) || {}
  named_tags = named_tags.map { |k, v| [k.to_s, v.to_s] }.to_h
  tags = context.delete(:tags)
  named_tags.merge!("tag" => tags.join(", ")) { |_, v1, v2| "#{v1}, #{v2}" } if tags
  named_tags.map { |k, v| [k[0...32], v[0...256]] }.to_h
end

def extract_user!(*sources)


the above keys is already present.
Any additional value nested in a :user key will be added, provided any of

Keys :username and :ip_address will be used verbatim.
Keys :user_id and :user_email will be used as :id and :email respectively.

Extract user data from named tags or payload.
def extract_user!(*sources)
  keys = {user_id: :id, username: :username, user_email: :email, ip_address: :ip_address}
  user = {}
  sources.each do |source|
    keys.each do |source_key, target_key|
      value = source.delete(source_key)
      user[target_key] = value if value
    end
  end
  return if user.empty?
  sources.each do |source|
    extras = source.delete(:user)
    user.merge!(extras) if extras.is_a?(Hash)
  end
  user
end

def initialize(level: :error, **args, &block)

Default: SemanticLogger.application
Name of this application to appear in log messages.
application: [String]

Default: SemanticLogger.host
Name of this host to appear in log messages.
host: [String]

The Proc must return true or false.
Proc: Only include log messages where the supplied Proc returns true
regular expression. All other messages will be ignored.
RegExp: Only include log messages where the class name matches the supplied.
filter: [Regexp|Proc]

Default: Use the built-in formatter (See: #call)
the output from this appender
An instance of a class that implements #call, or a Proc to be used to format
formatter: [Object|Proc|Symbol|Hash]

Default: :error
Override the log level for this appender.
level: [:trace | :debug | :info | :warn | :error | :fatal]
Parameters

Create Appender
def initialize(level: :error, **args, &block)
  # Replace the Sentry Ruby logger so that we can identify its log
  # messages and not forward them to Sentry
  ::Sentry.init { |config| config.logger = SemanticLogger[::Sentry] } unless ::Sentry.initialized?
  super
end

def log(log)

Send an error notification to sentry
def log(log)
  # Ignore logs coming from Sentry itself
  return false if log.name == "Sentry"
  context = formatter.call(log, self)
  payload = context.delete(:payload) || {}
  named_tags = context[:named_tags] || {}
  transaction_name = named_tags.delete(:transaction_name)
  user = extract_user!(named_tags, payload)
  tags = extract_tags!(context)
  fingerprint = payload.delete(:fingerprint)
  ::Sentry.with_scope do |scope|
    scope.set_user(user) if user
    scope.set_level(context.delete(:level)) if context[:level]
    scope.set_fingerprint(fingerprint) if fingerprint
    scope.set_transaction_name(transaction_name) if transaction_name
    scope.set_tags(tags)
    scope.set_extras(context)
    scope.set_extras(payload)
    if log.exception
      ::Sentry.capture_exception(log.exception)
    elsif log.backtrace
      ::Sentry.capture_message(context[:message], backtrace: log.backtrace)
    else
      ::Sentry.capture_message(context[:message])
    end
  end
  true
end