ez_logs_agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +57 -0
- data/CONFIGURATION.md +752 -0
- data/FAQ.md +574 -0
- data/LICENSE.txt +21 -0
- data/QUICKSTART.md +390 -0
- data/README.md +1021 -0
- data/RELEASING.md +55 -0
- data/Rakefile +8 -0
- data/lib/ez_logs_agent/actor.rb +57 -0
- data/lib/ez_logs_agent/actor_validator.rb +51 -0
- data/lib/ez_logs_agent/buffer.rb +83 -0
- data/lib/ez_logs_agent/capturers/active_job_capturer.rb +270 -0
- data/lib/ez_logs_agent/capturers/database_capturer.rb +467 -0
- data/lib/ez_logs_agent/capturers/job_capturer.rb +238 -0
- data/lib/ez_logs_agent/configuration.rb +186 -0
- data/lib/ez_logs_agent/configuration_validator.rb +139 -0
- data/lib/ez_logs_agent/correlation.rb +40 -0
- data/lib/ez_logs_agent/event_builder.rb +281 -0
- data/lib/ez_logs_agent/flush_scheduler.rb +99 -0
- data/lib/ez_logs_agent/logger.rb +62 -0
- data/lib/ez_logs_agent/middleware/http_request.rb +1094 -0
- data/lib/ez_logs_agent/railtie.rb +353 -0
- data/lib/ez_logs_agent/resource_extractor.rb +172 -0
- data/lib/ez_logs_agent/retry_sender.rb +120 -0
- data/lib/ez_logs_agent/transport.rb +91 -0
- data/lib/ez_logs_agent/version.rb +5 -0
- data/lib/ez_logs_agent.rb +42 -0
- data/lib/generators/ez_logs_agent/install/install_generator.rb +94 -0
- data/lib/generators/ez_logs_agent/install/templates/ez_logs_agent.rb.tt +128 -0
- data/lib/tasks/ez_logs_agent.rake +110 -0
- data/script/publish-to-public.sh +113 -0
- data/sig/ez_logs_agent.rbs +4 -0
- metadata +178 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EzLogsAgent
|
|
4
|
+
# FlushScheduler orchestrates periodic flushing of buffered events to the server.
|
|
5
|
+
#
|
|
6
|
+
# Responsibilities:
|
|
7
|
+
# - Start a single background thread that wakes up every `send_interval` seconds
|
|
8
|
+
# - Flush Buffer and send events via RetrySender
|
|
9
|
+
# - Shut down cleanly when requested
|
|
10
|
+
#
|
|
11
|
+
# Non-responsibilities:
|
|
12
|
+
# - Does NOT retry (RetrySender handles that)
|
|
13
|
+
# - Does NOT interpret Transport results
|
|
14
|
+
# - Does NOT manage Rails lifecycle (Railtie handles that)
|
|
15
|
+
# - Does NOT mutate or inspect events
|
|
16
|
+
class FlushScheduler
|
|
17
|
+
class << self
|
|
18
|
+
# Start the background flush thread
|
|
19
|
+
# Idempotent: safe to call multiple times
|
|
20
|
+
def start
|
|
21
|
+
return if running?
|
|
22
|
+
|
|
23
|
+
@stop_requested = false
|
|
24
|
+
@thread = Thread.new { run_loop }
|
|
25
|
+
|
|
26
|
+
Logger.debug("[FlushScheduler] Started")
|
|
27
|
+
rescue => error
|
|
28
|
+
Logger.error("[FlushScheduler] Failed to start: #{error.class} - #{error.message}")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Stop the background flush thread
|
|
32
|
+
# Blocks until thread exits
|
|
33
|
+
# Idempotent: safe to call multiple times
|
|
34
|
+
def stop
|
|
35
|
+
return unless running?
|
|
36
|
+
|
|
37
|
+
@stop_requested = true
|
|
38
|
+
@thread.join if @thread
|
|
39
|
+
|
|
40
|
+
Logger.debug("[FlushScheduler] Stopped")
|
|
41
|
+
rescue => error
|
|
42
|
+
Logger.error("[FlushScheduler] Failed to stop: #{error.class} - #{error.message}")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Check if the scheduler is currently running
|
|
46
|
+
def running?
|
|
47
|
+
@thread&.alive? == true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# Background loop: sleep → flush → send → repeat
|
|
53
|
+
def run_loop
|
|
54
|
+
loop do
|
|
55
|
+
break if @stop_requested
|
|
56
|
+
|
|
57
|
+
sleep_interval
|
|
58
|
+
break if @stop_requested
|
|
59
|
+
|
|
60
|
+
flush_and_send
|
|
61
|
+
end
|
|
62
|
+
rescue => error
|
|
63
|
+
Logger.error("[FlushScheduler] Loop crashed: #{error.class} - #{error.message}")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Sleep for configured interval
|
|
67
|
+
def sleep_interval
|
|
68
|
+
interval = send_interval
|
|
69
|
+
sleep(interval)
|
|
70
|
+
rescue => error
|
|
71
|
+
Logger.error("[FlushScheduler] Sleep failed: #{error.message}")
|
|
72
|
+
sleep(5) # Defensive fallback
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Flush buffer and send events
|
|
76
|
+
def flush_and_send
|
|
77
|
+
events = Buffer.flush
|
|
78
|
+
return if events.nil? || events.empty?
|
|
79
|
+
|
|
80
|
+
RetrySender.send(events)
|
|
81
|
+
rescue => error
|
|
82
|
+
Logger.error("[FlushScheduler] Flush and send failed: #{error.class} - #{error.message}")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Get send_interval from configuration with defensive fallback
|
|
86
|
+
def send_interval
|
|
87
|
+
interval = EzLogsAgent.configuration.send_interval
|
|
88
|
+
return 5 if interval.nil?
|
|
89
|
+
return 5 if !interval.is_a?(Numeric)
|
|
90
|
+
return 5 if interval <= 0
|
|
91
|
+
|
|
92
|
+
interval
|
|
93
|
+
rescue => error
|
|
94
|
+
Logger.error("[FlushScheduler] Failed to read send_interval: #{error.message}")
|
|
95
|
+
5
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EzLogsAgent
|
|
4
|
+
# Minimal, defensive logging utility for the gem.
|
|
5
|
+
# Delegates to Rails.logger when available, falls back to STDERR.
|
|
6
|
+
# Never raises exceptions, never crashes the host application.
|
|
7
|
+
module Logger
|
|
8
|
+
LOG_LEVELS = {
|
|
9
|
+
debug: 0,
|
|
10
|
+
info: 1,
|
|
11
|
+
warn: 2,
|
|
12
|
+
error: 3
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
def debug(message)
|
|
17
|
+
log(:debug, message)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def info(message)
|
|
21
|
+
log(:info, message)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def warn(message)
|
|
25
|
+
log(:warn, message)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def error(message)
|
|
29
|
+
log(:error, message)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def log(level, message)
|
|
35
|
+
# Early return if this log level should not be logged
|
|
36
|
+
return unless should_log?(level)
|
|
37
|
+
|
|
38
|
+
prefixed_message = "[EzLogsAgent] #{message}"
|
|
39
|
+
|
|
40
|
+
if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
|
41
|
+
Rails.logger.public_send(level, prefixed_message)
|
|
42
|
+
else
|
|
43
|
+
# Fallback to stderr when Rails.logger is not available
|
|
44
|
+
# Note: should_log? already checked above, so this respects log_level
|
|
45
|
+
$stderr.puts("[#{level.upcase}] #{prefixed_message}")
|
|
46
|
+
end
|
|
47
|
+
rescue => e
|
|
48
|
+
# Defensive: logging must never crash the host application.
|
|
49
|
+
# Silently swallow any logging errors.
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def should_log?(level)
|
|
54
|
+
configured_level = EzLogsAgent.configuration.log_level
|
|
55
|
+
LOG_LEVELS[level] >= LOG_LEVELS[configured_level]
|
|
56
|
+
rescue => e
|
|
57
|
+
# If we can't determine log level, allow logging (fail open).
|
|
58
|
+
true
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|