@@ -30,17 +30,29 @@ class ConfigLoader
30
30
# @return [Hash] Merged configuration
31
31
def self . load ( config_path : nil )
32
32
config = DEFAULT_CONFIG . dup
33
+ overrides = [ ]
33
34
34
35
# Load from file if path provided
35
36
if config_path . is_a? ( String ) && File . exist? ( config_path )
36
37
file_config = load_config_file ( config_path )
37
- config . merge! ( file_config ) if file_config
38
- elsif config_path . is_a? ( Hash )
39
- config . merge! ( config_path )
38
+ if file_config
39
+ overrides << "file config"
40
+ config . merge! ( file_config )
41
+ end
42
+ end
43
+
44
+ # Override with environment variables (before programmatic config)
45
+ env_config = load_env_config
46
+ if env_config . any?
47
+ overrides << "environment variables"
48
+ config . merge! ( env_config )
40
49
end
41
50
42
- # Override with environment variables
43
- config . merge! ( load_env_config )
51
+ # Programmatic config has highest priority
52
+ if config_path . is_a? ( Hash )
53
+ overrides << "programmatic config"
54
+ config . merge! ( config_path )
55
+ end
44
56
45
57
# Convert string keys to symbols for consistency
46
58
config = symbolize_keys ( config )
@@ -51,6 +63,13 @@ def self.load(config_path: nil)
51
63
config [ :production ] = false
52
64
end
53
65
66
+ # Log overrides if any were made
67
+ if overrides . any?
68
+ # Use puts for now since logger might not be initialized yet
69
+ # This will be replaced with proper logging once the logger is available
70
+ puts "INFO: Configuration overrides applied from: #{ overrides . join ( ', ' ) } "
71
+ end
72
+
54
73
return config
55
74
end
56
75
@@ -93,8 +112,9 @@ def self.load_config_file(file_path)
93
112
end
94
113
95
114
result
96
- rescue => _e
97
- # In production, we'd log this error
115
+ rescue => e
116
+ # Log this error with meaningful information
117
+ puts "ERROR: Failed to load config file '#{ file_path } ': #{ e . message } "
98
118
nil
99
119
end
100
120
@@ -105,26 +125,35 @@ def self.load_env_config
105
125
env_config = { }
106
126
107
127
env_mappings = {
128
+ "HOOKS_HANDLER_DIR" => :handler_dir ,
108
129
"HOOKS_HANDLER_PLUGIN_DIR" => :handler_plugin_dir ,
109
130
"HOOKS_AUTH_PLUGIN_DIR" => :auth_plugin_dir ,
131
+ "HOOKS_LIFECYCLE_PLUGIN_DIR" => :lifecycle_plugin_dir ,
132
+ "HOOKS_INSTRUMENTS_PLUGIN_DIR" => :instruments_plugin_dir ,
110
133
"HOOKS_LOG_LEVEL" => :log_level ,
111
134
"HOOKS_REQUEST_LIMIT" => :request_limit ,
112
135
"HOOKS_REQUEST_TIMEOUT" => :request_timeout ,
113
136
"HOOKS_ROOT_PATH" => :root_path ,
114
137
"HOOKS_HEALTH_PATH" => :health_path ,
115
138
"HOOKS_VERSION_PATH" => :version_path ,
116
139
"HOOKS_ENVIRONMENT" => :environment ,
117
- "HOOKS_ENDPOINTS_DIR" => :endpoints_dir
140
+ "HOOKS_ENDPOINTS_DIR" => :endpoints_dir ,
141
+ "HOOKS_USE_CATCHALL_ROUTE" => :use_catchall_route ,
142
+ "HOOKS_SYMBOLIZE_PAYLOAD" => :symbolize_payload ,
143
+ "HOOKS_NORMALIZE_HEADERS" => :normalize_headers
118
144
}
119
145
120
146
env_mappings . each do |env_key , config_key |
121
147
value = ENV [ env_key ]
122
148
next unless value
123
149
124
- # Convert numeric values
150
+ # Convert values to appropriate types
125
151
case config_key
126
152
when :request_limit , :request_timeout
127
153
env_config [ config_key ] = value . to_i
154
+ when :use_catchall_route , :symbolize_payload , :normalize_headers
155
+ # Convert string to boolean
156
+ env_config [ config_key ] = %w[ true 1 yes on ] . include? ( value . downcase )
128
157
else
129
158
env_config [ config_key ] = value
130
159
end
0 commit comments