11# frozen_string_literal: true
22
3+ require_relative '../security/log_sanitizer'
4+
35module Html2rss
46 module Web
57 ##
@@ -9,8 +11,26 @@ module SentryLogs
911 OMIT = Object . new . freeze
1012 ALLOWED_LEVELS = %i[ debug info warn error fatal ] . freeze
1113 SENSITIVE_ATTRIBUTE_KEYS = %w[ actor email ip remote_ip user_agent username x_forwarded_for ] . freeze
14+ BREADCRUMB_KEYS = %i[ event_name security_event outcome request_id route_group strategy component details ] . freeze
15+ BREADCRUMB_CATEGORY_KEYS = %i[ event_name security_event component ] . freeze
16+ BREADCRUMB_MESSAGE_KEYS = %i[ message event_name security_event component ] . freeze
1217
1318 class << self
19+ # @param payload [Hash{Symbol=>Object}]
20+ # @return [void]
21+ def record_breadcrumb ( payload )
22+ return unless breadcrumb_enabled?
23+
24+ ::Sentry . add_breadcrumb (
25+ category : breadcrumb_category ( payload ) ,
26+ message : breadcrumb_message ( payload ) ,
27+ level : breadcrumb_level ( payload ) ,
28+ data : breadcrumb_data ( payload )
29+ )
30+ rescue StandardError
31+ nil
32+ end
33+
1434 # @param payload [Hash{Symbol=>Object}]
1535 # @return [void]
1636 def emit ( payload )
@@ -31,6 +51,13 @@ def enabled?
3151 !logger . nil?
3252 end
3353
54+ # @return [Boolean]
55+ def breadcrumb_enabled?
56+ RuntimeEnv . sentry_enabled? &&
57+ defined? ( ::Sentry ) &&
58+ ::Sentry . respond_to? ( :add_breadcrumb )
59+ end
60+
3461 # @return [Object, nil]
3562 def logger
3663 return unless defined? ( ::Sentry ) && ::Sentry . respond_to? ( :logger )
@@ -54,6 +81,34 @@ def message(payload)
5481 payload [ :component ] || 'html2rss-web log'
5582 end
5683
84+ # @param payload [Hash{Symbol=>Object}]
85+ # @return [String]
86+ def breadcrumb_category ( payload )
87+ breadcrumb_label ( payload , 'html2rss-web' , BREADCRUMB_CATEGORY_KEYS )
88+ end
89+
90+ # @param payload [Hash{Symbol=>Object}]
91+ # @return [String]
92+ def breadcrumb_message ( payload )
93+ breadcrumb_label ( payload , 'html2rss-web log' , BREADCRUMB_MESSAGE_KEYS )
94+ end
95+
96+ # @param payload [Hash{Symbol=>Object}]
97+ # @return [String]
98+ def breadcrumb_level ( payload )
99+ requested_level = payload . fetch ( :level , 'info' ) . to_s . downcase
100+ return 'warning' if requested_level == 'warn'
101+ return requested_level if ALLOWED_LEVELS . map ( &:to_s ) . include? ( requested_level )
102+
103+ 'info'
104+ end
105+
106+ # @param payload [Hash{Symbol=>Object}]
107+ # @return [Hash{Symbol=>Object}]
108+ def breadcrumb_data ( payload )
109+ LogSanitizer . sanitize_details ( payload ) . slice ( *BREADCRUMB_KEYS )
110+ end
111+
57112 # @param payload [Hash{Symbol=>Object}]
58113 # @return [Hash{Symbol=>Object}]
59114 def attributes ( payload )
@@ -98,6 +153,14 @@ def sanitize_array(key, values)
98153 def sensitive_key? ( key )
99154 SENSITIVE_ATTRIBUTE_KEYS . include? ( key . to_s )
100155 end
156+
157+ # @param payload [Hash{Symbol=>Object}]
158+ # @param fallback [String]
159+ # @param keys [Array<Symbol>]
160+ # @return [String]
161+ def breadcrumb_label ( payload , fallback , keys )
162+ keys . lazy . map { |key | payload [ key ] } . find ( &:itself ) || fallback
163+ end
101164 end
102165 end
103166 end
0 commit comments