Skip to content

Commit 367ac4f

Browse files
committed
fix server_process? - don't try to parse argv, check for known defined server constants
1 parent ef05502 commit 367ac4f

File tree

3 files changed

+88
-3
lines changed

3 files changed

+88
-3
lines changed

lib/log_struct/concerns/configuration.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ module Configuration
1010
module ClassMethods
1111
extend T::Sig
1212

13-
SERVER_COMMAND_ARGS = T.let(["server", "s"].freeze, T::Array[String])
1413
CONSOLE_COMMAND_ARGS = T.let(["console", "c"].freeze, T::Array[String])
1514
EMPTY_ARGV = T.let([].freeze, T::Array[String])
1615
CI_FALSE_VALUES = T.let(["false", "0", "no"].freeze, T::Array[String])
@@ -133,8 +132,21 @@ def console_process?
133132
sig { returns(T::Boolean) }
134133
def server_process?
135134
return true if logstruct_server_mode?
135+
# Check for web servers - the module/gem is loaded at require time
136+
return true if defined?(::Puma::CLI) # puma CLI is defined when running `puma` command
137+
return true if defined?(::Puma::Server) # or Puma::Server if already loaded
138+
return true if defined?(::Unicorn::HttpServer)
139+
return true if defined?(::Thin::Server)
140+
return true if defined?(::Falcon::Server)
141+
return true if defined?(::Rails::Server)
142+
return true if sidekiq_server?
143+
144+
false
145+
end
136146

137-
current_argv.any? { |arg| SERVER_COMMAND_ARGS.include?(arg) }
147+
sig { returns(T::Boolean) }
148+
def sidekiq_server?
149+
!!(defined?(::Sidekiq) && ::Sidekiq.respond_to?(:server?) && ::Sidekiq.server?)
138150
end
139151

140152
sig { returns(T::Boolean) }

lib/log_struct/semantic_logger/setup.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def self.configure_semantic_logger(app)
101101

102102
sig { params(app: T.untyped).returns(Symbol) }
103103
def self.determine_log_level(app)
104-
if app.config.log_level
104+
level = if app.config.log_level
105105
app.config.log_level
106106
elsif Rails.env.production?
107107
:info
@@ -110,6 +110,8 @@ def self.determine_log_level(app)
110110
else
111111
:debug
112112
end
113+
# Rails config.log_level can be a String or Symbol
114+
level.is_a?(String) ? level.to_sym : level
113115
end
114116

115117
sig { params(app: T.untyped).void }

rails_test_app/templates/test/integration/puma_integration_test.rb

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,77 @@
55
require "timeout"
66

77
class PumaIntegrationTest < ActiveSupport::TestCase
8+
# Test that running `puma` directly (without `rails server`) auto-enables LogStruct
9+
# via Puma::Server detection - no LOGSTRUCT_ENABLED env var needed
10+
def test_puma_direct_auto_enables_logstruct
11+
port = 32124
12+
env = {
13+
"RAILS_ENV" => "production",
14+
"RAILS_LOG_TO_STDOUT" => "1",
15+
"SECRET_KEY_BASE" => "test_secret_key_base_for_production_mode_1234567890"
16+
}
17+
18+
# Run puma directly, NOT rails server
19+
cmd = ["bundle", "exec", "puma", "-p", port.to_s, "-e", "production"]
20+
21+
Open3.popen3(env, *cmd) do |_stdin, stdout, stderr, wait_thr|
22+
begin
23+
lines = []
24+
Timeout.timeout(15) do
25+
while (line = stdout.gets)
26+
lines << line.strip
27+
# Puma outputs "Listening on" when ready
28+
break if line.include?("Listening on")
29+
end
30+
end
31+
32+
# Send TERM to trigger graceful shutdown
33+
begin
34+
Process.kill("TERM", wait_thr.pid)
35+
rescue Errno::ESRCH
36+
# Process already exited
37+
end
38+
39+
# Collect shutdown output
40+
Timeout.timeout(10) do
41+
while (line = stdout.gets)
42+
lines << line.strip
43+
end
44+
end
45+
rescue Timeout::Error
46+
# Fall through and ensure process is terminated
47+
ensure
48+
begin
49+
Process.kill("TERM", wait_thr.pid)
50+
rescue Errno::ESRCH
51+
# already dead
52+
end
53+
end
54+
55+
output = lines.join("\n")
56+
stderr_output = stderr.read
57+
58+
# Find JSON log lines - LogStruct should be enabled via Puma::Server detection
59+
json_lines = lines.filter_map do |l|
60+
JSON.parse(l) if l.strip.start_with?("{")
61+
rescue JSON::ParserError
62+
nil
63+
end
64+
65+
assert_predicate json_lines,
66+
:any?,
67+
"Expected JSON logs from direct puma invocation (Puma::Server detection should enable LogStruct).\n" \
68+
"STDOUT: #{output}\nSTDERR: #{stderr_output}"
69+
70+
# Verify we got puma lifecycle logs
71+
puma_logs = json_lines.select { |h| h["src"] == "puma" }
72+
73+
assert_predicate puma_logs,
74+
:any?,
75+
"Expected puma lifecycle logs. JSON logs: #{json_lines.inspect}"
76+
end
77+
end
78+
879
def test_rails_server_emits_structured_puma_logs_and_on_exit
980
port = 32123
1081
env = {

0 commit comments

Comments
 (0)