skylight 0.3.21 → 0.4.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +0 -4
  3. data/ext/extconf.rb +92 -47
  4. data/ext/libskylight.yml +4 -4
  5. data/ext/skylight_native.c +248 -286
  6. data/lib/skylight.rb +19 -114
  7. data/lib/skylight/api.rb +1 -1
  8. data/lib/skylight/config.rb +176 -146
  9. data/lib/skylight/data/cacert.pem +717 -719
  10. data/lib/skylight/formatters/http.rb +1 -1
  11. data/lib/skylight/instrumenter.rb +28 -35
  12. data/lib/skylight/native.rb +58 -72
  13. data/lib/skylight/normalizers.rb +0 -1
  14. data/lib/skylight/normalizers/active_record/sql.rb +0 -4
  15. data/lib/skylight/probes/excon/middleware.rb +3 -1
  16. data/lib/skylight/probes/net_http.rb +3 -1
  17. data/lib/skylight/subscriber.rb +0 -4
  18. data/lib/skylight/trace.rb +189 -0
  19. data/lib/skylight/util.rb +10 -12
  20. data/lib/skylight/util/hostname.rb +17 -0
  21. data/lib/skylight/util/http.rb +33 -36
  22. data/lib/skylight/util/logging.rb +20 -1
  23. data/lib/skylight/util/multi_io.rb +21 -0
  24. data/lib/skylight/util/native_ext_fetcher.rb +83 -69
  25. data/lib/skylight/util/platform.rb +67 -0
  26. data/lib/skylight/util/ssl.rb +50 -0
  27. data/lib/skylight/version.rb +1 -1
  28. metadata +9 -34
  29. data/ext/rust_support/ruby.h +0 -93
  30. data/ext/skylight.h +0 -85
  31. data/ext/skylight.map +0 -4
  32. data/ext/test/extconf.rb +0 -18
  33. data/ext/test/skylight_native_test.c +0 -82
  34. data/ext/test/skylight_test.h +0 -20
  35. data/lib/skylight/formatters.rb +0 -6
  36. data/lib/skylight/messages.rb +0 -21
  37. data/lib/skylight/messages/error.rb +0 -15
  38. data/lib/skylight/messages/hello.rb +0 -13
  39. data/lib/skylight/messages/trace.rb +0 -179
  40. data/lib/skylight/messages/trace_envelope.rb +0 -19
  41. data/lib/skylight/metrics.rb +0 -9
  42. data/lib/skylight/metrics/ewma.rb +0 -69
  43. data/lib/skylight/metrics/meter.rb +0 -58
  44. data/lib/skylight/metrics/process_cpu_gauge.rb +0 -65
  45. data/lib/skylight/metrics/process_mem_gauge.rb +0 -34
  46. data/lib/skylight/util/conversions.rb +0 -9
  47. data/lib/skylight/util/queue.rb +0 -96
  48. data/lib/skylight/util/task.rb +0 -172
  49. data/lib/skylight/util/uniform_sample.rb +0 -63
  50. data/lib/skylight/worker.rb +0 -19
  51. data/lib/skylight/worker/builder.rb +0 -73
  52. data/lib/skylight/worker/collector.rb +0 -274
  53. data/lib/skylight/worker/connection.rb +0 -87
  54. data/lib/skylight/worker/connection_set.rb +0 -56
  55. data/lib/skylight/worker/embedded.rb +0 -24
  56. data/lib/skylight/worker/metrics_reporter.rb +0 -104
  57. data/lib/skylight/worker/server.rb +0 -336
  58. data/lib/skylight/worker/standalone.rb +0 -421
@@ -1,124 +1,37 @@
1
- require 'rbconfig'
2
- require 'socket'
3
1
  require 'skylight/version'
4
2
 
5
3
  module Skylight
6
4
  # @api private
7
- TRACE_ENV_KEY = 'SKYLIGHT_ENABLE_TRACE_LOGS'.freeze
5
+ TRACE_ENV_KEY = 'SKYLIGHT_ENABLE_TRACE_LOGS'.freeze
8
6
 
9
- # @api private
10
- STANDALONE_ENV_KEY = 'SKYLIGHT_STANDALONE'.freeze
11
-
12
- # @api private
13
- STANDALONE_ENV_VAL = 'server'.freeze
14
-
15
- # @api private
16
- # Whether or not the native extension is present
17
- @@has_native_ext = false
18
-
19
- def self.native?
20
- @@has_native_ext
21
- end
22
-
23
- begin
24
- unless ENV["SKYLIGHT_DISABLE_AGENT"]
25
- # First attempt to require the native extension
26
- require 'skylight_native'
27
-
28
- # If nothing was thrown, then the native extension is present
29
- @@has_native_ext = true
30
-
31
- # Require ruby support for the native extension
32
- require 'skylight/native'
33
- end
34
- rescue LoadError
35
- raise if ENV.key?("SKYLIGHT_REQUIRED")
36
- end
7
+ # Load the native agent
8
+ require 'skylight/native'
37
9
 
38
10
  if defined?(Rails)
39
11
  require 'skylight/railtie'
40
12
  end
41
13
 
42
- # @api private
43
- def self.check_install_errors(config)
44
- # Note: An unsupported arch doesn't count as an error.
45
- install_log = File.expand_path("../../ext/install.log", __FILE__)
46
-
47
- if File.exist?(install_log) && File.read(install_log) =~ /ERROR/
48
- config.alert_logger.error \
49
- "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension failed to install. " \
50
- "Please check #{install_log} and notify support@skylight.io." \
51
- "The missing extension will not affect the functioning of your application."
52
- end
53
- end
54
-
55
- # @api private
56
- def self.warn_skylight_native_missing(config)
57
- # TODO: Dumping the error messages this way is pretty hacky
58
- is_rails = defined?(Rails)
59
- env_name = is_rails ? Rails.env : "development"
60
-
61
- if env_name == "development" || env_name == "test"
62
- config.alert_logger.warn \
63
- "[SKYLIGHT] [#{Skylight::VERSION}] Running Skylight in #{env_name} mode. " \
64
- "No data will be reported until you deploy your app.\n" \
65
- "(To disable this message, set `alert_log_file` in your config.)"
66
- else
67
- config.alert_logger.error \
68
- "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension for your platform wasn't found. " \
69
- "The monitoring portion of Skylight is only supported on production servers running 32- or " \
70
- "64-bit Linux. The missing extension will not affect the functioning of your application " \
71
- "and you can continue local development without data being reported. If you are on a " \
72
- "supported platform, please contact support at support@skylight.io."
73
- end
74
- end
75
-
76
- # @api private
77
- def self.daemon?
78
- ENV[STANDALONE_ENV_KEY] == STANDALONE_ENV_VAL
79
- end
80
-
81
- unless daemon?
82
- require 'active_support/notifications'
83
- require 'skylight/compat' # Require after AS::N
84
-
85
- # Require VM specific things
86
- require 'skylight/vm/gc'
87
- end
14
+ require 'active_support/notifications'
15
+ require 'skylight/compat' # Require after AS::N
16
+
17
+ # Require VM specific things
18
+ require 'skylight/config'
19
+ require 'skylight/gc'
20
+ require 'skylight/helpers'
21
+ require 'skylight/instrumenter'
22
+ require 'skylight/middleware'
23
+ require 'skylight/trace'
24
+ require 'skylight/vm/gc'
25
+ require 'skylight/util'
88
26
 
27
+ # Used from the CLI
89
28
  autoload :Api, 'skylight/api'
90
29
  autoload :CLI, 'skylight/cli'
91
- autoload :Config, 'skylight/config'
92
- autoload :Helpers, 'skylight/helpers'
93
- autoload :Formatters, 'skylight/formatters'
94
- autoload :GC, 'skylight/gc'
95
- autoload :Instrumenter, 'skylight/instrumenter'
96
- autoload :Messages, 'skylight/messages'
97
- autoload :Metrics, 'skylight/metrics'
98
- autoload :Middleware, 'skylight/middleware'
99
30
  autoload :Normalizers, 'skylight/normalizers'
100
31
  autoload :Subscriber, 'skylight/subscriber'
101
- autoload :Worker, 'skylight/worker'
102
-
103
- # Skylight::Util is defined by the native ext so we can't autoload
104
- require 'skylight/util'
105
-
106
- # ==== Exceptions ====
107
-
108
- # @api private
109
- class IpcProtoError < RuntimeError; end
110
-
111
- # @api private
112
- class WorkerStateError < RuntimeError; end
113
-
114
- # @api private
115
- class ConfigError < RuntimeError; end
116
32
 
117
33
  # @api private
118
- class TraceError < RuntimeError; end
119
-
120
- # @api private
121
- class SerializeError < RuntimeError; end
34
+ class ConfigError < RuntimeError; end
122
35
 
123
36
  # @api private
124
37
  TIERS = %w(
@@ -159,9 +72,9 @@ module Skylight
159
72
  end
160
73
 
161
74
  if block_given?
162
- inst.trace(endpoint, cat, title) { yield }
75
+ inst.trace(endpoint, cat || DEFAULT_CATEGORY, title) { yield }
163
76
  else
164
- inst.trace(endpoint, cat, title)
77
+ inst.trace(endpoint, cat || DEFAULT_CATEGORY, title)
165
78
  end
166
79
  end
167
80
 
@@ -207,13 +120,5 @@ module Skylight
207
120
  inst.disable { yield }
208
121
  end
209
122
 
210
- # @api private
211
- RUBYBIN = File.join(
212
- RbConfig::CONFIG['bindir'],
213
- "#{RbConfig::CONFIG['ruby_install_name']}#{RbConfig::CONFIG['EXEEXT']}")
214
-
215
- # Called by the standalone agent
216
- Worker::Server.boot if daemon?
217
-
218
123
  require 'skylight/probes'
219
124
  end
@@ -27,7 +27,7 @@ module Skylight
27
27
  end
28
28
  end
29
29
 
30
- def initialize(config, service = :accounts)
30
+ def initialize(config, service = :auth)
31
31
  @config = config
32
32
  @http = Util::HTTP.new(config, service)
33
33
  end
@@ -1,82 +1,92 @@
1
+ require 'uri'
1
2
  require 'yaml'
2
3
  require 'fileutils'
3
- require 'logger'
4
4
  require 'thread'
5
- require 'socket'
6
-
7
- class AlertLoggerIO
8
- def initialize(config)
9
- @config = config
10
- end
11
-
12
- def write(*args)
13
- STDERR.write *args
14
- @config.logger.<<(*args)
15
- end
16
-
17
- def close
18
- end
19
- end
5
+ require 'openssl'
6
+ require 'skylight/util/hostname'
7
+ require 'skylight/util/logging'
8
+ require 'skylight/util/platform'
9
+ require 'skylight/util/ssl'
20
10
 
21
11
  module Skylight
22
12
  class Config
23
13
  # @api private
24
14
  MUTEX = Mutex.new
25
15
 
26
- def self.default_hostname
27
- if hostname = Socket.gethostname
28
- hostname.strip!
29
- hostname = nil if hostname == ''
30
- end
31
-
32
- hostname || "gen-#{SecureRandom.uuid}"
33
- end
34
-
35
16
  # Map environment variable keys with Skylight configuration keys
36
17
  ENV_TO_KEY = {
37
- 'ROOT' => :'root',
38
- 'LOG_FILE' => :'log_file',
39
- 'LOG_LEVEL' => :'log_level',
40
- 'ALERT_LOG_FILE' => :'alert_log_file',
41
- 'APPLICATION' => :'application',
42
- 'AUTHENTICATION' => :'authentication',
43
- 'HOSTNAME' => :'hostname',
44
- 'SKIP_VALIDATION' => :'skip_validation',
45
- 'AGENT_INTERVAL' => :'agent.interval',
46
- 'AGENT_KEEPALIVE' => :'agent.keepalive',
47
- 'AGENT_LOCKFILE' => :'agent.lockfile',
48
- 'AGENT_SAMPLE_SIZE' => :'agent.sample',
49
- 'AGENT_SOCKFILE_PATH' => :'agent.sockfile_path',
50
- 'AGENT_STRATEGY' => :'agent.strategy',
18
+ # == Authentication ==
19
+ 'AUTHENTICATION' => :'authentication',
20
+
21
+ # == Version ==
22
+ 'VERSION' => :'version',
23
+
24
+ # == App settings ==
25
+ 'ROOT' => :'root',
26
+ 'APPLICATION' => :'application',
27
+ 'HOSTNAME' => :'hostname',
28
+
29
+ # == Logging ==
30
+ 'LOG_FILE' => :'log_file',
31
+ 'LOG_LEVEL' => :'log_level',
32
+ 'ALERT_LOG_FILE' => :'alert_log_file',
33
+
34
+ # == Proxy ==
35
+ 'PROXY_URL' => :'proxy_url',
36
+
37
+ # == Skylight Remote ==
38
+ "AUTH_URL" => :'auth_url',
39
+ "AUTH_HTTP_DEFLATE" => :'auth_http_deflate',
40
+ "AUTH_HTTP_CONNECT_TIMEOUT" => :'auth_http_connect_timeout',
41
+ "AUTH_HTTP_READ_TIMEOUT" => :'auth_http_read_timeout',
42
+ "REPORT_URL" => :'report_url',
43
+ "REPORT_HTTP_DEFLATE" => :'report_http_deflate',
44
+ "REPORT_HTTP_CONNECT_TIMEOUT" => :'report_http_connect_timeout',
45
+ "REPORT_HTTP_READ_TIMEOUT" => :'report_http_read_timeout',
46
+
47
+ # == Native agent settings ==
48
+ #
49
+ "LAZY_START" => :'daemon.lazy_start',
50
+ "DAEMON_EXEC_PATH" => :'daemon.exec_path',
51
+ "DAEMON_LIB_PATH" => :'daemon.lib_path',
52
+ "PIDFILE_PATH" => :'daemon.pidfile_path',
53
+ "SOCKDIR_PATH" => :'daemon.sockdir_path',
54
+ "BATCH_QUEUE_DEPTH" => :'daemon.batch_queue_depth',
55
+ "BATCH_SAMPLE_SIZE" => :'daemon.batch_sample_size',
56
+ "BATCH_FLUSH_INTERVAL" => :'daemon.batch_flush_interval',
57
+ "DAEMON_TICK_INTERVAL" => :'daemon.tick_interval',
58
+ "DAEMON_SANITY_CHECK_INTERVAL" => :'daemon.sanity_check_interval',
59
+ "DAEMON_INACTIVITY_TIMEOUT" => :'daemon.inactivity_timeout',
60
+ "CLIENT_MAX_TRIES" => :'daemon.max_connect_tries',
61
+ "CLIENT_CONN_TRY_WIN" => :'daemon.connect_try_window',
62
+ "MAX_PRESPAWN_JITTER" => :'daemon.max_prespawn_jitter',
63
+ "DAEMON_WAIT_TIMEOUT" => :'daemon.wait_timeout',
64
+ "CLIENT_CHECK_INTERVAL" => :'daemon.client_check_interval',
65
+ "CLIENT_QUEUE_DEPTH" => :'daemon.client_queue_depth',
66
+ "CLIENT_WRITE_TIMEOUT" => :'daemon.client_write_timeout',
67
+ "SSL_CERT_PATH" => :'daemon.ssl_cert_path',
68
+ "SSL_CERT_DIR" => :'daemon.ssl_cert_dir',
69
+
70
+ # == Legacy settings ==
71
+ #
51
72
  'AGENT_MAX_MEMORY' => :'agent.max_memory',
52
- 'REPORT_HOST' => :'report.host',
53
- 'REPORT_PORT' => :'report.port',
54
- 'REPORT_SSL' => :'report.ssl',
55
- 'REPORT_DEFLATE' => :'report.deflate',
56
- 'REPORT_PROXY_ADDR' => :'report.proxy_addr',
57
- 'REPORT_PROXY_PORT' => :'report.proxy_port',
58
- 'REPORT_PROXY_USER' => :'report.proxy_user',
59
- 'REPORT_PROXY_PASS' => :'report.proxy_user',
60
- 'ACCOUNTS_HOST' => :'accounts.host',
61
- 'ACCOUNTS_PORT' => :'accounts.port',
62
- 'ACCOUNTS_SSL' => :'accounts.ssl',
63
- 'ACCOUNTS_DEFLATE' => :'accounts.deflate',
64
- 'ACCOUNTS_PROXY_ADDR' => :'accounts.proxy_addr',
65
- 'ACCOUNTS_PROXY_PORT' => :'accounts.proxy_port',
66
- 'ACCOUNTS_PROXY_USER' => :'accounts.proxy_user',
67
- 'ACCOUNTS_PROXY_PASS' => :'accounts.proxy_user',
68
73
  'ME_AUTHENTICATION' => :'me.authentication',
69
74
  'ME_CREDENTIALS_PATH' => :'me.credentials_path',
70
- 'METRICS_REPORT_INTERVAL' => :'metrics.report_interval',
71
- 'TEST_CONSTANT_FLUSH' => :'test.constant_flush',
72
75
  'TEST_IGNORE_TOKEN' => :'test.ignore_token' }
73
76
 
74
77
  # Default values for Skylight configuration keys
75
78
  DEFAULTS = {
79
+ :'version' => VERSION,
80
+ :'auth_url' => 'https://www.skylight.io/agent/authenticate',
81
+ :'daemon.lazy_start' => true,
82
+ :'daemon.ssl_cert_path' => Util::SSL.ca_cert_file_or_default,
83
+ :'daemon.ssl_cert_dir' => Util::SSL.ca_cert_dir,
84
+
85
+ # == Legacy ==
76
86
  :'log_file' => '-'.freeze,
77
87
  :'log_level' => 'INFO'.freeze,
78
88
  :'alert_log_file' => '-'.freeze,
79
- :'hostname' => default_hostname,
89
+ :'hostname' => Util::Hostname.default_hostname,
80
90
  :'agent.keepalive' => 60,
81
91
  :'agent.interval' => 5,
82
92
  :'agent.sample' => 200,
@@ -91,7 +101,16 @@ module Skylight
91
101
  :'accounts.deflate' => false,
92
102
  :'me.credentials_path' => '~/.skylight',
93
103
  :'metrics.report_interval' => 60
94
- }.freeze
104
+ }
105
+
106
+ if Skylight.native?
107
+ native_path = Skylight.libskylight_path
108
+
109
+ DEFAULTS[:'daemon.lib_path'] = native_path
110
+ DEFAULTS[:'daemon.exec_path'] = File.join(native_path, 'skylightd')
111
+ end
112
+
113
+ DEFAULTS.freeze
95
114
 
96
115
  REQUIRED = {
97
116
  :'authentication' => "authentication token",
@@ -99,10 +118,50 @@ module Skylight
99
118
  :'report.host' => "skylight remote host",
100
119
  :'report.port' => "skylight remote port" }
101
120
 
121
+ ALWAYS_INCLUDE_IN_ENV = [
122
+ :version,
123
+ :'daemon.lazy_start',
124
+ :'daemon.lib_path',
125
+ :'daemon.exec_path',
126
+ :'daemon.ssl_cert_dir',
127
+ :'daemon.ssl_cert_path' ]
128
+
102
129
  VALIDATORS = {
103
130
  :'agent.interval' => [lambda { |v, c| Integer === v && v > 0 }, "must be an integer greater than 0"]
104
131
  }
105
132
 
133
+ # @api private
134
+ attr_reader :environment
135
+
136
+ # @api private
137
+ def initialize(*args)
138
+ attrs = {}
139
+
140
+ if Hash === args.last
141
+ attrs = args.pop.dup
142
+ end
143
+
144
+ @values = {}
145
+ @priority = {}
146
+ @regexp = nil
147
+
148
+ p = attrs.delete(:priority)
149
+
150
+ if @environment = args[0]
151
+ @regexp = /^#{Regexp.escape(@environment)}\.(.+)$/
152
+ end
153
+
154
+ attrs.each do |k, v|
155
+ self[k] = v
156
+ end
157
+
158
+ if p
159
+ p.each do |k, v|
160
+ @priority[k.to_sym] = v
161
+ end
162
+ end
163
+ end
164
+
106
165
  def self.load(path = nil, environment = nil, env = ENV)
107
166
  attrs = {}
108
167
  version = nil
@@ -137,6 +196,10 @@ module Skylight
137
196
  def self.remap_env(env)
138
197
  ret = {}
139
198
 
199
+ return ret unless env
200
+
201
+ ret[:proxy_url] = detect_proxy_url(env)
202
+
140
203
  env.each do |k, val|
141
204
  # Support deprecated SK_ key prefix
142
205
  next unless k =~ /^(?:SK|SKYLIGHT)_(.+)$/
@@ -152,40 +215,15 @@ module Skylight
152
215
  else val
153
216
  end
154
217
  end
155
- end if env
218
+ end
156
219
 
157
220
  ret
158
221
  end
159
222
 
160
- # @api private
161
- attr_reader :environment
162
-
163
- # @api private
164
- def initialize(*args)
165
- attrs = {}
166
-
167
- if Hash === args.last
168
- attrs = args.pop.dup
169
- end
170
-
171
- @values = {}
172
- @priority = {}
173
- @regexp = nil
174
-
175
- p = attrs.delete(:priority)
176
-
177
- if @environment = args[0]
178
- @regexp = /^#{Regexp.escape(@environment)}\.(.+)$/
179
- end
180
-
181
- attrs.each do |k, v|
182
- self[k] = v
183
- end
184
-
185
- if p
186
- p.each do |k, v|
187
- @priority[k.to_sym] = v
188
- end
223
+ def self.detect_proxy_url(env)
224
+ if u = env['HTTP_PROXY'] || env['http_proxy']
225
+ u = "http://#{u}" unless u =~ %r[://]
226
+ u
189
227
  end
190
228
  end
191
229
 
@@ -207,24 +245,6 @@ module Skylight
207
245
  true
208
246
  end
209
247
 
210
- # @api private
211
- def validate_token
212
- return :ok if skip_validation?
213
-
214
- http_auth = Util::HTTP.new(self, :accounts, timeout: 5)
215
-
216
- res = http_auth.get("/agent/authenticate?hostname=#{URI.escape(self[:'hostname'])}")
217
-
218
- case res.status
219
- when 200...300
220
- :ok
221
- when 400...500
222
- :invalid
223
- else
224
- :unknown
225
- end
226
- end
227
-
228
248
  def key?(key)
229
249
  key = key.to_sym
230
250
  @priority.key?(key) || @values.key?(key)
@@ -280,12 +300,32 @@ module Skylight
280
300
 
281
301
  alias []= set
282
302
 
303
+ def duration_ms(key, default = nil)
304
+ if (v = self[key]) && v.to_s =~ /^\s*(\d+)(s|sec|ms|micros|nanos)?\s*$/
305
+ v = $1.to_i
306
+ case $2
307
+ when "ms"
308
+ v
309
+ when "micros"
310
+ v / 1_000
311
+ when "nanos"
312
+ v / 1_000_000
313
+ else # "s", "sec", nil
314
+ v * 1000
315
+ end
316
+ else
317
+ default
318
+ end
319
+ end
320
+
283
321
  def to_env
284
- ret = {}
322
+ ret = []
285
323
 
286
324
  ENV_TO_KEY.each do |k, v|
287
- if (c = get(v)) != DEFAULTS[v]
288
- ret["SKYLIGHT_#{k}"] = cast_for_env(c)
325
+ c = get(v)
326
+ # Always need to pass daemon lib_path config even when default
327
+ if c != DEFAULTS[v] || ALWAYS_INCLUDE_IN_ENV.include?(v)
328
+ ret << "SKYLIGHT_#{k}" << cast_for_env(c) if c
289
329
  end
290
330
  end
291
331
 
@@ -313,21 +353,11 @@ authentication: #{self[:authentication]}
313
353
  #
314
354
  #
315
355
 
316
- # @api private
317
- def worker
318
- @worker ||= Worker::Builder.new(self)
319
- end
320
-
321
356
  # @api private
322
357
  def gc
323
358
  @gc ||= GC.new(self, get('gc.profiler', VM::GC.new))
324
359
  end
325
360
 
326
- # @api private
327
- def constant_flush?
328
- get('test.constant_flush')
329
- end
330
-
331
361
  # @api private
332
362
  def ignore_token?
333
363
  get('test.ignore_token')
@@ -339,29 +369,8 @@ authentication: #{self[:authentication]}
339
369
 
340
370
  def logger
341
371
  @logger ||=
342
- begin
343
- MUTEX.synchronize do
344
- unless l = @logger
345
- out = get(:'log_file')
346
- out = STDOUT if out == '-'
347
-
348
- unless IO === out
349
- out = File.expand_path(out, root)
350
- FileUtils.mkdir_p(File.dirname(out))
351
- end
352
-
353
- l = Logger.new(out)
354
- l.level =
355
- case get(:'log_level')
356
- when /^debug$/i then Logger::DEBUG
357
- when /^info$/i then Logger::INFO
358
- when /^warn$/i then Logger::WARN
359
- when /^error$/i then Logger::ERROR
360
- end
361
- end
362
-
363
- l
364
- end
372
+ MUTEX.synchronize do
373
+ load_logger
365
374
  end
366
375
  end
367
376
 
@@ -377,7 +386,7 @@ authentication: #{self[:authentication]}
377
386
  out = get(:'alert_log_file')
378
387
 
379
388
  if out == '-'
380
- out = AlertLoggerIO.new(self)
389
+ out = Util::AlertLogger.new(load_logger)
381
390
  elsif !(IO === out)
382
391
  out = File.expand_path(out, root)
383
392
  FileUtils.mkdir_p(File.dirname(out))
@@ -396,9 +405,31 @@ authentication: #{self[:authentication]}
396
405
  @alert_logger = logger
397
406
  end
398
407
 
399
-
400
408
  private
401
409
 
410
+ def load_logger
411
+ unless l = @logger
412
+ out = get(:'log_file')
413
+ out = STDOUT if out == '-'
414
+
415
+ unless IO === out
416
+ out = File.expand_path(out, root)
417
+ FileUtils.mkdir_p(File.dirname(out))
418
+ end
419
+
420
+ l = Logger.new(out)
421
+ l.level =
422
+ case get(:'log_level')
423
+ when /^debug$/i then Logger::DEBUG
424
+ when /^info$/i then Logger::INFO
425
+ when /^warn$/i then Logger::WARN
426
+ when /^error$/i then Logger::ERROR
427
+ end
428
+ end
429
+
430
+ l
431
+ end
432
+
402
433
  def cast_for_env(v)
403
434
  case v
404
435
  when true then 'true'
@@ -407,6 +438,5 @@ authentication: #{self[:authentication]}
407
438
  else v.to_s
408
439
  end
409
440
  end
410
-
411
441
  end
412
442
  end