td-logger 0.2.3 → 0.2.4

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.
data/ChangeLog CHANGED
@@ -1,4 +1,14 @@
1
1
 
2
+ == 2011-09-13 version 0.2.4
3
+
4
+ * Increase flush_interval from 10 sec to 5 mins gradually
5
+ * Flush buffered logs when Rails stops
6
+ * Adds 'elapsed' column to access logs
7
+ * Use TREASURE_DATA_API_KEY environment variable by default
8
+ * Enable event logger if apikey is available with default database name
9
+ and access log table name
10
+
11
+
2
12
  == 2011-09-08 version 0.2.3
3
13
 
4
14
  * Loggers use STDERR instead of STDOUT
@@ -35,10 +35,20 @@ module Agent
35
35
  data = {}
36
36
  Thread.current['td.access_log'] = data
37
37
  env['td.access_log'] = data
38
+ env['td.access_time'] = Time.now
38
39
  end
39
40
 
40
41
  Middleware.after do |env,result|
41
42
  data = env['td.access_log'] || {}
43
+ access_time = env['td.access_time']
44
+
45
+ # add 'elapsed' column
46
+ if access_time
47
+ elapsed = Time.now - access_time
48
+ data['elapsed'] = elapsed
49
+ # set 'time' column to access time
50
+ data['time'] = access_time
51
+ end
42
52
 
43
53
  ACCESS_LOG_PRESET_ENV_KEYS.each_pair {|key,val|
44
54
  data[key] ||= env[val] if env[val]
@@ -86,14 +86,31 @@ EOF
86
86
  require 'yaml'
87
87
  require 'erb'
88
88
  logger = ::Rails.logger || ::Logger.new(STDERR)
89
+
90
+ unless File.exist?(CONFIG_PATH)
91
+ apikey = ENV['TREASURE_DATA_API_KEY'] || ENV['TD_API_KEY']
92
+ unless apikey
93
+ logger.warn "TREASURE_DATA_API_KEY environment variable is not set"
94
+ logger.warn "#{CONFIG_PATH} does not exist."
95
+ logger.warn "Disabling Treasure Data logger."
96
+ return
97
+ end
98
+ return Config.new({
99
+ 'apikey' => apikey,
100
+ 'database' => ENV['TREASURE_DATA_DB'] || "rails_#{rails_env}",
101
+ 'access_log_table' => ENV['TREASURE_DATA_TABLE'] || 'web_access',
102
+ 'auto_create_table' => true
103
+ })
104
+ end
105
+
89
106
  begin
90
107
  src = File.read("#{rails_root}/#{CONFIG_PATH}")
91
108
  yaml = ERB.new(src).result
92
109
  env_conf = YAML.load(yaml)
93
110
  rescue
94
- logger.warn "Can't load #{CONFIG_PATH} file."
95
- logger.warn " #{$!}"
96
- logger.warn "Put the following file:"
111
+ logger.warn "Can't load #{CONFIG_PATH} file: #{$!}"
112
+ logger.warn "Disabling Treasure Data logger."
113
+ logger.warn "Example:"
97
114
  logger.warn CONFIG_SAMPLE
98
115
  return
99
116
  end
@@ -2,9 +2,27 @@
2
2
  module TreasureData
3
3
  module Logger
4
4
 
5
- # TODO shutdown handler (deadlock)
6
5
 
7
6
  class TreasureDataLogger < Fluent::Logger::LoggerBase
7
+ module Finalizable
8
+ require 'delegate'
9
+ def new(*args, &block)
10
+ obj = allocate
11
+ obj.instance_eval { initialize(*args, &block) }
12
+ dc = DelegateClass(obj.class).new(obj)
13
+ ObjectSpace.define_finalizer(dc, finalizer(obj))
14
+ dc
15
+ end
16
+
17
+ def finalizer(obj)
18
+ fin = obj.method(:finalize)
19
+ proc {|id|
20
+ fin.call
21
+ }
22
+ end
23
+ end
24
+ extend Finalizable
25
+
8
26
  def initialize(apikey, tag, auto_create_table)
9
27
  require 'thread'
10
28
  require 'stringio'
@@ -18,7 +36,9 @@ class TreasureDataLogger < Fluent::Logger::LoggerBase
18
36
 
19
37
  @tag = tag
20
38
  @auto_create_table = auto_create_table
39
+
21
40
  @logger = ::Logger.new(STDERR)
41
+ @logger.level = ::Logger::INFO
22
42
 
23
43
  @client = TreasureData::Client.new(apikey)
24
44
 
@@ -28,7 +48,8 @@ class TreasureDataLogger < Fluent::Logger::LoggerBase
28
48
  @queue = []
29
49
 
30
50
  @chunk_limit = 8*1024*1024
31
- @flush_interval = 300
51
+ @flush_interval = 10
52
+ @max_flush_interval = 300
32
53
  @retry_wait = 1.0
33
54
  @retry_limit = 8
34
55
 
@@ -41,11 +62,21 @@ class TreasureDataLogger < Fluent::Logger::LoggerBase
41
62
  attr_accessor :logger
42
63
 
43
64
  def close
44
- @finish = true
45
- @mutex.synchronize {
46
- @flush_now = true
47
- @cond.signal
48
- }
65
+ unless @finish
66
+ @finish = true
67
+ @mutex.synchronize {
68
+ @flush_now = true
69
+ @cond.signal
70
+ }
71
+ @upload_thread.join
72
+
73
+ @map.each {|(db,table),buffer|
74
+ upload(db, table, buffer)
75
+ }
76
+ @queue.each {|tuple|
77
+ upload(*tuple)
78
+ }
79
+ end
49
80
  end
50
81
 
51
82
  def post(tag, record)
@@ -70,29 +101,32 @@ class TreasureDataLogger < Fluent::Logger::LoggerBase
70
101
  end
71
102
 
72
103
  def upload_main
73
- @mutex.lock
74
- until @finish
75
- now = Time.now.to_i
104
+ @mutex.lock
105
+ until @finish
106
+ now = Time.now.to_i
107
+
108
+ if @next_time <= now || (@flush_now && @error_count == 0)
109
+ @mutex.unlock
110
+ begin
111
+ flushed = try_flush
112
+ ensure
113
+ @mutex.lock
114
+ end
115
+ @flush_now = false
116
+ end
76
117
 
77
- if @next_time <= now || (@flush_now && @error_count == 0)
78
- @mutex.unlock
79
- begin
80
- try_flush
81
- ensure
82
- @mutex.lock
118
+ if @error_count == 0
119
+ if flushed && @flush_interval < @max_flush_interval
120
+ @flush_interval = [@flush_interval + 60, @max_flush_interval].min
121
+ end
122
+ next_wait = @flush_interval
123
+ else
124
+ next_wait = @retry_wait * (2 ** (@error_count-1))
83
125
  end
84
- @flush_now = false
85
- end
126
+ @next_time = next_wait + now
86
127
 
87
- if @error_count == 0
88
- next_wait = @flush_interval
89
- else
90
- next_wait = @retry_wait * (2 ** (@error_count-1))
128
+ cond_wait(next_wait)
91
129
  end
92
- @next_time = next_wait + now
93
-
94
- cond_wait(next_wait)
95
- end
96
130
 
97
131
  rescue
98
132
  @logger.error "Unexpected error: #{$!}"
@@ -113,6 +147,8 @@ class TreasureDataLogger < Fluent::Logger::LoggerBase
113
147
  end
114
148
  end
115
149
 
150
+ flushed = false
151
+
116
152
  until @queue.empty?
117
153
  tuple = @queue.first
118
154
 
@@ -120,12 +156,13 @@ class TreasureDataLogger < Fluent::Logger::LoggerBase
120
156
  upload(*tuple)
121
157
  @queue.shift
122
158
  @error_count = 0
159
+ flushed = true
123
160
  rescue
124
161
  if @error_count < @retry_limit
125
- @logger.error "Failed to upload logs to Treasure Data, retrying: #{$!}"
162
+ @logger.error "Failed to import logs to Treasure Data, retrying: #{$!}"
126
163
  @error_count += 1
127
164
  else
128
- @logger.error "Failed to upload logs to Treasure Data, trashed: #{$!}"
165
+ @logger.error "Failed to import logs to Treasure Data, trashed: #{$!}"
129
166
  $!.backtrace.each {|bt|
130
167
  @logger.info bt
131
168
  }
@@ -135,14 +172,17 @@ class TreasureDataLogger < Fluent::Logger::LoggerBase
135
172
  return
136
173
  end
137
174
  end
175
+
176
+ flushed
138
177
  end
139
178
 
140
179
  def upload(db, table, buffer)
141
- out = StringIO.new
142
- Zlib::GzipWriter.wrap(out) {|gz| gz.write buffer }
143
- stream = StringIO.new(out.string)
144
-
180
+ @logger.debug "Importing logs to #{db}.#{table} table on TreasureData"
145
181
  begin
182
+ out = StringIO.new
183
+ Zlib::GzipWriter.wrap(out) {|gz| gz.write buffer }
184
+ stream = StringIO.new(out.string)
185
+
146
186
  @client.import(db, table, "msgpack.gz", stream, stream.size)
147
187
  rescue TreasureData::NotFoundError
148
188
  unless @auto_create_table
@@ -159,8 +199,8 @@ class TreasureDataLogger < Fluent::Logger::LoggerBase
159
199
  end
160
200
  end
161
201
 
162
- def e(s)
163
- CGI.escape(s.to_s)
202
+ def finalize
203
+ close
164
204
  end
165
205
 
166
206
  if ConditionVariable.new.method(:wait).arity == 1
@@ -1,7 +1,7 @@
1
1
  module TreasureData
2
2
  module Logger
3
3
 
4
- VERSION = '0.2.3'
4
+ VERSION = '0.2.4'
5
5
 
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: td-logger
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 3
10
- version: 0.2.3
9
+ - 4
10
+ version: 0.2.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sadayuki Furuhashi
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-09 00:00:00 +09:00
18
+ date: 2011-09-13 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency