1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
# frozen_string_literal: true
module Sentry
# Event type that represents a log entry with its attributes
#
# @see https://develop.sentry.dev/sdk/telemetry/logs/#log-envelope-item-payload
class LogEvent
TYPE = "log"
DEFAULT_PARAMETERS = [].freeze
DEFAULT_ATTRIBUTES = {}.freeze
SERIALIZEABLE_ATTRIBUTES = %i[
level
body
timestamp
environment
release
server_name
trace_id
attributes
contexts
]
SENTRY_ATTRIBUTES = {
"sentry.trace.parent_span_id" => :parent_span_id,
"sentry.environment" => :environment,
"sentry.release" => :release,
"sentry.address" => :server_name,
"sentry.sdk.name" => :sdk_name,
"sentry.sdk.version" => :sdk_version,
"sentry.message.template" => :template,
"sentry.origin" => :origin
}
PARAMETER_PREFIX = "sentry.message.parameter"
USER_ATTRIBUTES = {
"user.id" => :user_id,
"user.name" => :user_username,
"user.email" => :user_email
}
LEVELS = %i[trace debug info warn error fatal].freeze
attr_accessor :level, :body, :template, :attributes, :user, :origin
attr_reader :configuration, *(SERIALIZEABLE_ATTRIBUTES - %i[level body attributes])
SERIALIZERS = %i[
attributes
body
level
parent_span_id
sdk_name
sdk_version
template
timestamp
trace_id
user_id
user_username
user_email
].map { |name| [name, :"serialize_#{name}"] }.to_h
VALUE_TYPES = Hash.new("string").merge!({
TrueClass => "boolean",
FalseClass => "boolean",
Integer => "integer",
Float => "double"
}).freeze
TOKEN_REGEXP = /%\{(\w+)\}/
def initialize(configuration: Sentry.configuration, **options)
@configuration = configuration
@type = TYPE
@server_name = configuration.server_name
@environment = configuration.environment
@release = configuration.release
@timestamp = Sentry.utc_now
@level = options.fetch(:level)
@body = options[:body]
@template = @body if is_template?
@attributes = options[:attributes] || DEFAULT_ATTRIBUTES
@user = options[:user] || {}
@origin = options[:origin]
@contexts = {}
end
def to_hash
SERIALIZEABLE_ATTRIBUTES.each_with_object({}) do |name, memo|
memo[name] = serialize(name)
end
end
private
def serialize(name)
serializer = SERIALIZERS[name]
if serializer
__send__(serializer)
else
public_send(name)
end
end
def serialize_level
level.to_s
end
def serialize_sdk_name
Sentry.sdk_meta["name"]
end
def serialize_sdk_version
Sentry.sdk_meta["version"]
end
def serialize_timestamp
timestamp.to_f
end
def serialize_trace_id
contexts.dig(:trace, :trace_id)
end
def serialize_parent_span_id
contexts.dig(:trace, :parent_span_id)
end
def serialize_body
if parameters.empty?
body
elsif parameters.is_a?(Hash)
body % parameters
else
sprintf(body, *parameters)
end
end
def serialize_user_id
user[:id]
end
def serialize_user_username
user[:username]
end
def serialize_user_email
user[:email]
end
def serialize_template
template if has_parameters?
end
def serialize_attributes
hash = {}
attributes.each do |key, value|
hash[key] = attribute_hash(value)
end
SENTRY_ATTRIBUTES.each do |key, name|
if (value = serialize(name))
hash[key] = attribute_hash(value)
end
end
USER_ATTRIBUTES.each do |key, name|
if (value = serialize(name))
hash[key] = value
end
end
hash
end
def attribute_hash(value)
{ value: value, type: value_type(value) }
end
def value_type(value)
VALUE_TYPES[value.class]
end
def parameters
@parameters ||= begin
return DEFAULT_PARAMETERS unless template
parameters = template_tokens.empty? ?
attributes.fetch(:parameters, DEFAULT_PARAMETERS) : attributes.slice(*template_tokens)
if parameters.is_a?(Hash)
parameters.each do |key, value|
attributes["#{PARAMETER_PREFIX}.#{key}"] = value
end
else
parameters.each_with_index do |param, index|
attributes["#{PARAMETER_PREFIX}.#{index}"] = param
end
end
end
end
def template_tokens
@template_tokens ||= body.scan(TOKEN_REGEXP).flatten.map(&:to_sym)
end
def is_template?
body.include?("%s") || TOKEN_REGEXP.match?(body)
end
def has_parameters?
attributes.keys.any? { |key| key.start_with?(PARAMETER_PREFIX) }
end
end
end
|