td-logger 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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