td-logger 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,4 +1,12 @@
1
1
 
2
+ == 2011-08-28 version 0.2.0
3
+
4
+ * Rewritten
5
+ * Supported access logging: td_access_log or TreasureData.access_log
6
+ * Supported model change logging: td_enable_model_tracer
7
+ * Supported other logging: TreasureData.log
8
+
9
+
2
10
  == 2011-08-21 version 0.1.1
3
11
 
4
12
  * Updated library dependencies
@@ -13,44 +13,85 @@ edit +environment.rb+ and add to the initalizer block:
13
13
 
14
14
  And then add +config/treasure_data.yml+ file as following:
15
15
 
16
- # logging to Treasure Data directry
16
+ # logging to Treasure Data directly
17
17
  development:
18
18
  apikey: "YOUR_API_KEY"
19
19
  database: myapp
20
+ access_log_table: access
20
21
  auto_create_table: true
21
22
 
22
23
  # logging via td-agent
23
24
  production:
24
25
  agent: "localhost:24224"
25
- tag: myapp
26
+ tag: td.myapp
27
+ access_log_table: access
26
28
 
27
29
  # disable logging
28
30
  test:
29
31
 
30
- === Logging actions
32
+ === Logging access logs
31
33
 
32
- Add 'add_td_tracer' line to your controller classes:
34
+ Following information will be logged automatically:
35
+
36
+ * controller name ('controller' column)
37
+ * action name ('action' column)
38
+ * remote host ip address ('remote_addr' column)
39
+ * http status code ('status' column)
40
+ * http referer ('refer' column)
41
+
42
+ To add information to the log, call 'td_access_log' method in a Controller:
33
43
 
34
44
  class YourController < ApplicationController
35
45
  def myaction
36
- # ...
46
+ td_access_log[:column] = "value"
47
+ end
48
+ end
49
+
50
+ Or call 'TreasureData.access_log' method outside of a Controller:
51
+
52
+ class MyHelperModule
53
+ def mymethod
54
+ TreasureData.access_log[:column] = "value"
37
55
  end
38
- add_td_tracer :myaction, 'mytable'
39
56
  end
40
57
 
41
- It logs {"controller":"your","action":"myaction"}. Additionally, routing parameters are included automatically.
42
58
 
43
- You can add environment variables by adding 'extra' option as follows:
59
+ === Logging model changes
60
+
61
+ Add 'td_enable_model_tracer' line to your Model class:
62
+
63
+ class MyModel < ActiveRecord::Base
64
+ td_enable_model_tracer :mytable
65
+ end
66
+
67
+ It logs all columns when the model is changed. Use :only option to limit columns to log:
68
+
69
+ class MyModel < ActiveRecord::Base
70
+ td_enable_model_tracer :mytable, :only => [:id, :mycol]
71
+ end
44
72
 
45
- # logs client address on the 'addr' column
46
- add_td_tracer :myaction, 'mytable', :extra=>{:REMOTE_ADDR=>:addr}
73
+ Alternatively, use :except option to except columns to log:
47
74
 
48
- # logs referer and path info
49
- add_td_tracer :myaction, 'mytable', :extra=>{:HTTP_REFERER=>:referer, :PATH_INFO=>:path}
75
+ class MyModel < ActiveRecord::Base
76
+ td_enable_model_tracer :mytable, :except => [:created_at]
77
+ end
50
78
 
51
79
  Add 'static' option to add constant key-value pairs:
52
80
 
53
- add_td_tracer :myaction, 'mytable', :static=>{:version=>1}
81
+ class MyModel < ActiveRecord::Base
82
+ td_enable_model_tracer :mytable, :except => [:created_at], :static => {'model'=>'my'}
83
+ end
84
+
85
+
86
+ === Logging other logs
87
+
88
+ You can log anytime using 'TreasureData.log' method:
89
+
90
+ class MyClass
91
+ def mymethod
92
+ TreasureData.log('mytable', {:col1=>"val1", :col2=>"val2"}
93
+ end
94
+ end
54
95
 
55
96
 
56
97
  == Copyright
@@ -1,266 +1,32 @@
1
+ require 'fluent/logger'
1
2
 
2
3
  module TreasureData
3
- module Logger
4
4
 
5
-
6
- class Config
7
- def initialize(conf)
8
- if agent = conf['agent']
9
- host, port = agent.split(':',2)
10
- port = (port || 24224).to_i
11
- @agent_host = host
12
- @agent_port = port
13
-
14
- @tag = conf['tag']
15
- @tag ||= conf['database']
16
- raise "'tag' nor 'database' options are not set" unless @tag
17
-
18
- else
19
- @apikey = conf['apikey']
20
- raise "'apikey' option is not set" unless @apikey
21
-
22
- @database = conf['database']
23
- raise "'database' option is not set" unless @database
24
-
25
- @auto_create_table = !!conf['auto_create_table']
26
- end
27
- end
28
-
29
- attr_reader :agent_host, :agent_port, :tag
30
- attr_reader :apikey, :database, :auto_create_table
31
-
32
- def agent_mode?
33
- @agent_host != nil
34
- end
5
+ def self.open(apikey, database, auto_create_table=false)
6
+ require 'td/logger/tdlog'
7
+ TreasureData::Logger::TreasureDataLogger.open(apikey, database, auto_create_table)
35
8
  end
36
9
 
37
-
10
+ def self.open_agent(tag, agent_host, agent_port)
11
+ Fluent::Logger::FluentLogger.open(tag, agent_host, agent_port)
38
12
  end
39
- end
40
-
41
-
42
- module TreasureData
43
-
44
13
 
45
14
  def self.log(tag, record)
46
15
  record['time'] ||= Time.now.to_i
47
16
  Fluent::Logger.post(tag, record)
48
17
  end
49
18
 
50
-
51
- module Logger
52
- module RailsAgent
53
-
54
- CONFIG_SAMPLE = <<EOF
55
- defaults: &defaults
56
- apikey: "YOUR_API_KEY"
57
- database: myapp
58
- table: access
59
-
60
- test:
61
- <<: *defaults
62
-
63
- development:
64
- <<: *defaults
65
-
66
- production:
67
- <<: *defaults
68
- EOF
69
-
70
- CONFIG_PATH = 'config/treasure_data.yml'
71
-
72
- def self.init(rails)
73
- c = read_config(rails)
74
- return unless c
75
-
76
- require 'fluent/logger'
77
- if c.agent_mode?
78
- Fluent::Logger::FluentLogger.open(c.tag, c.agent_host, c.agent_port)
79
- else
80
- require 'td/logger/tdlog'
81
- TreasureDataLogger.open(c.apikey, c.database, c.auto_create_table)
82
- end
83
-
84
- rails.middleware.use Middleware
85
- ActionController::Base.class_eval do
86
- include ::TreasureData::Logger::RailsAgent::ControllerLogger
87
- end
88
- end
89
-
90
- def self.read_config(rails)
91
- logger = Rails.logger || ::Logger.new(STDOUT)
92
- begin
93
- yaml = YAML.load_file("#{RAILS_ROOT}/#{CONFIG_PATH}")
94
- rescue
95
- logger.warn "Can't load #{CONFIG_PATH} file."
96
- logger.warn " #{$!}"
97
- logger.warn "Put the following file:"
98
- logger.warn sample
99
- return
100
- end
101
-
102
- conf = yaml[RAILS_ENV]
103
- unless conf
104
- logger.warn "#{CONFIG_PATH} doesn't include setting for current environment (#{RAILS_ENV})."
105
- logger.warn "Disabling Treasure Data logger."
106
- return
107
- end
108
-
109
- begin
110
- return Config.new(conf)
111
- rescue
112
- logger.warn "#{CONFIG_PATH}: #{$!}."
113
- logger.warn "Disabling Treasure Data logger."
114
- return
115
- end
116
- end
117
-
118
- class Middleware
119
- def initialize(app, options={})
120
- @app = app
121
- end
122
-
123
- def call(env)
124
- r = @app.call(env)
125
-
126
- if m = env['treasure_data.log_method']
127
- m.call(env)
128
- end
129
-
130
- r
131
- end
132
-
133
- def self.set_log_method(env, method)
134
- env['treasure_data.log_method'] = method
135
- end
136
19
  end
137
20
 
138
- module ControllerLogger
139
- def self.included(mod)
140
- mod.extend(ModuleMethods)
141
- end
142
-
143
- class ActionLogger
144
- PARAM_KEY = if defined? Rails
145
- if Rails.respond_to?(:version) && Rails.version =~ /^3/
146
- # Rails 3
147
- 'action_dispatch.request.path_parameters'
148
- else
149
- # Rails 2
150
- 'action_controller.request.path_parameters'
151
- end
152
- else
153
- # Rack default
154
- 'rack.routing_args'
155
- end
156
-
157
- def initialize(method, tag, options)
158
- @method = method
159
- @tag = tag
160
21
 
161
- @only = nil
162
- @except = nil
163
- @extra = nil
164
- @static = {}
165
-
166
- if o = options[:only_params]
167
- @only = case o
168
- when Array
169
- o
170
- else
171
- [o]
172
- end.map {|e| e.to_s }
173
- end
174
-
175
- if o = options[:except_params]
176
- @except = case o
177
- when Array
178
- o
179
- else
180
- [o]
181
- end.map {|e| e.to_s }
182
- end
183
-
184
- if o = options[:extra]
185
- @extra = case o
186
- when Hash
187
- m = {}
188
- o.each_pair {|k,v| m[k.to_s] = v.to_s }
189
- m
190
- when Array
191
- o.map {|e|
192
- case e
193
- when Hash
194
- m = {}
195
- e.each_pair {|k,v| m[k.to_s] = v.to_s }
196
- m
197
- else
198
- {e.to_s => e.to_s}
199
- end
200
- }.inject({}) {|r,e| r.merge!(e) }
201
- else
202
- {o.to_s => o.to_s}
203
- end
204
- end
205
-
206
- if o = options[:static]
207
- o.each_pair {|k,v| @static[k] = v }
208
- end
209
- end
210
-
211
- def call(env)
212
- m = env[PARAM_KEY].dup || {}
213
-
214
- if @only
215
- m.reject! {|k,v| !@only.include?(k) }
216
- end
217
- if @except
218
- m.reject! {|k,v| @except.include?(k) }
219
- end
220
- if @extra
221
- @extra.each_pair {|k,v| m[v] = env[k] }
222
- end
223
-
224
- m.merge!(@static)
225
-
226
- ::TreasureData.log(@tag, m)
227
- end
228
- end
229
-
230
- module ModuleMethods
231
- def add_td_tracer(method, tag, options={})
232
- al = ActionLogger.new(method, tag, options)
233
- module_eval <<-EOF
234
- def #{method}_td_action_tracer_(*args, &block)
235
- ::TreasureData::Logger::RailsAgent::Middleware.set_log_method(request.env, method(:#{method}_td_action_trace_))
236
- #{method}_td_action_tracer_orig_(*args, &block)
237
- end
238
- EOF
239
- module_eval do
240
- define_method(:"#{method}_td_action_trace_", &al.method(:call))
241
- end
242
- alias_method "#{method}_td_action_tracer_orig_", method
243
- alias_method method, "#{method}_td_action_tracer_"
244
- end
22
+ class Time
23
+ def to_msgpack(out = '')
24
+ to_i.to_msgpack(out)
245
25
  end
246
26
  end
247
27
 
248
- end
249
- end
250
-
251
- end
252
28
 
253
29
  if defined? Rails
254
- if Rails.respond_to?(:version) && Rails.version =~ /^3/
255
- module TreasureData
256
- class Railtie < Rails::Railtie
257
- initializer "treasure_data_agent.start_plugin" do |app|
258
- TreasureData::Logger::RailsAgent.init(app.config)
259
- end
260
- end
261
- end
262
- else
263
- TreasureData::Logger::RailsAgent.init(Rails.configuration)
264
- end
30
+ require 'td/logger/agent/rails'
265
31
  end
266
32
 
@@ -0,0 +1,58 @@
1
+
2
+ module TreasureData
3
+ module Logger
4
+ module Agent
5
+
6
+ ACCESS_LOG_PARAM_ENV =
7
+ if defined? Rails
8
+ if Rails.respond_to?(:version) && Rails.version =~ /^3/
9
+ # Rails 3
10
+ 'action_dispatch.request.path_parameters'
11
+ else
12
+ # Rails 2
13
+ 'action_controller.request.path_parameters'
14
+ end
15
+ else
16
+ # Rack default
17
+ 'rack.routing_args'
18
+ end
19
+
20
+ ACCESS_LOG_PRESET_PARAM_KEYS = {
21
+ 'controller' => 'controller',
22
+ 'action' => 'action',
23
+ }
24
+
25
+ ACCESS_LOG_PRESET_ENV_KEYS = {
26
+ 'remote_addr' => 'REMOTE_ADDR',
27
+ 'referer' => 'HTTP_REFERER',
28
+ }
29
+
30
+ def self.enable_access_log(tag)
31
+ Middleware.before do |env|
32
+ data = {}
33
+ Thread.current['td.access_log'] = data
34
+ env['td.access_log'] = data
35
+ end
36
+
37
+ Middleware.after do |env,result|
38
+ data = env['td.access_log'] || {}
39
+
40
+ ACCESS_LOG_PRESET_ENV_KEYS.each_pair {|key,val|
41
+ data[key] ||= env[val] if env[val]
42
+ }
43
+
44
+ m = env[ACCESS_LOG_PARAM_ENV]
45
+ ACCESS_LOG_PRESET_PARAM_KEYS.each_pair {|key,val|
46
+ data[key] ||= m[val] if m[val]
47
+ }
48
+
49
+ # result code
50
+ data['status'] ||= result[0].to_i
51
+
52
+ TreasureData.log(tag, data)
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,41 @@
1
+
2
+ module TreasureData
3
+ module Logger
4
+ module Agent
5
+
6
+
7
+ class Middleware
8
+ @@before = []
9
+ @@after = []
10
+
11
+ def self.before(&block)
12
+ @@before << block
13
+ end
14
+
15
+ def self.after(&block)
16
+ @@after << block
17
+ end
18
+
19
+ def initialize(app, options={})
20
+ @app = app
21
+ end
22
+
23
+ def call(env)
24
+ @@before.each {|m|
25
+ m.call(env)
26
+ }
27
+
28
+ result = @app.call(env)
29
+
30
+ @@after.each {|m|
31
+ m.call(env, result)
32
+ }
33
+
34
+ result
35
+ end
36
+ end
37
+
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,134 @@
1
+ module TreasureData
2
+ module Logger
3
+ module Agent
4
+ require 'td/logger/agent/middleware'
5
+ require 'td/logger/agent/access_log'
6
+ require 'td/logger/agent/rails/controller'
7
+ require 'td/logger/agent/rails/model'
8
+
9
+ module Rails
10
+
11
+ CONFIG_PATH = 'config/treasure_data.yml'
12
+
13
+ CONFIG_SAMPLE = <<EOF
14
+ # logging to Treasure Data directly
15
+ development:
16
+ apikey: "YOUR_API_KEY"
17
+ database: myapp
18
+ access_log_table: access
19
+ auto_create_table: true
20
+
21
+ # logging via td-agent
22
+ production:
23
+ agent: "localhost:24224"
24
+ tag: td.myapp
25
+ access_log_table: access
26
+
27
+ # disable logging
28
+ test:
29
+ EOF
30
+
31
+ class Config
32
+ def initialize(conf)
33
+ if agent = conf['agent']
34
+ host, port = agent.split(':',2)
35
+ port = (port || 24224).to_i
36
+ @agent_host = host
37
+ @agent_port = port
38
+
39
+ @tag = conf['tag']
40
+ @tag ||= conf['database']
41
+ raise "'tag' nor 'database' options are not set" unless @tag
42
+
43
+ else
44
+ @apikey = conf['apikey']
45
+ raise "'apikey' option is not set" unless @apikey
46
+
47
+ @database = conf['database']
48
+ raise "'database' option is not set" unless @database
49
+
50
+ @auto_create_table = !!conf['auto_create_table']
51
+ end
52
+
53
+ @access_log_table = conf['access_log_table']
54
+ end
55
+
56
+ attr_reader :agent_host, :agent_port, :tag
57
+ attr_reader :apikey, :database, :auto_create_table
58
+ attr_reader :access_log_table
59
+
60
+ def agent_mode?
61
+ @agent_host != nil
62
+ end
63
+
64
+ def access_log_enabled?
65
+ !@access_log_table.nil? && !@access_log_table.empty?
66
+ end
67
+ end
68
+
69
+ def self.read_config(rails)
70
+ logger = ::Rails.logger || ::Logger.new(STDOUT)
71
+ begin
72
+ yaml = YAML.load_file("#{RAILS_ROOT}/#{CONFIG_PATH}")
73
+ rescue
74
+ logger.warn "Can't load #{CONFIG_PATH} file."
75
+ logger.warn " #{$!}"
76
+ logger.warn "Put the following file:"
77
+ logger.warn sample
78
+ return
79
+ end
80
+
81
+ conf = yaml[RAILS_ENV]
82
+ unless conf
83
+ logger.warn "#{CONFIG_PATH} doesn't include setting for current environment (#{RAILS_ENV})."
84
+ logger.warn "Disabling Treasure Data logger."
85
+ return
86
+ end
87
+
88
+ begin
89
+ return Config.new(conf)
90
+ rescue
91
+ logger.warn "#{CONFIG_PATH}: #{$!}."
92
+ logger.warn "Disabling Treasure Data logger."
93
+ return
94
+ end
95
+ end
96
+
97
+ def self.init(rails)
98
+ c = read_config(rails)
99
+ return unless c
100
+
101
+ if c.agent_mode?
102
+ ::TreasureData.open_agent(c.tag, c.agent_host, c.agent_port)
103
+ else
104
+ ::TreasureData.open(c.apikey, c.database, c.auto_create_table)
105
+ end
106
+
107
+ rails.middleware.use Agent::Middleware
108
+
109
+ if c.access_log_enabled?
110
+ Agent.enable_access_log(c.access_log_table)
111
+ end
112
+ Agent::Rails.init_controller
113
+ Agent::Rails.init_model
114
+ end
115
+
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ if defined? Rails
122
+ if Rails.respond_to?(:version) && Rails.version =~ /^3/
123
+ module TreasureData
124
+ class Railtie < Rails::Railtie
125
+ initializer "treasure_data_agent.start_plugin" do |app|
126
+ TreasureData::Logger::Agent::Rails.init(app.config)
127
+ end
128
+ end
129
+ end
130
+ else
131
+ TreasureData::Logger::Agent::Rails.init(Rails.configuration)
132
+ end
133
+ end
134
+
@@ -0,0 +1,32 @@
1
+ module TreasureData
2
+ module Logger
3
+ module Agent
4
+ module Rails
5
+
6
+ def self.init_controller
7
+ ms = ControllerMethods
8
+ modms = ControllerModuleMethods
9
+ ActionController::Base.class_eval do
10
+ include ms
11
+ extend modms
12
+ end
13
+ end
14
+
15
+ module ControllerMethods
16
+ def td_access_log
17
+ request.env['td.access_log'] ||= {}
18
+ end
19
+ end
20
+
21
+ module ControllerModuleMethods
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+
28
+ def self.access_log
29
+ Thread.current['td.access_log']
30
+ end
31
+
32
+ end
@@ -0,0 +1,79 @@
1
+ module TreasureData
2
+ module Logger
3
+ module Agent
4
+ module Rails
5
+
6
+ def self.init_model
7
+ ms = ModelMethods
8
+ modms = ModelModuleMethods
9
+ require 'active_record' unless defined?(ActiveRecord)
10
+ ActiveRecord::Base.class_eval do
11
+ include ms
12
+ extend modms
13
+ end
14
+ end
15
+
16
+ module ModelMethods
17
+ end
18
+
19
+ module ModelModuleMethods
20
+ def td_enable_model_tracer(tag, options={})
21
+ only = nil
22
+ except = nil
23
+ static = {}
24
+
25
+ if o = options[:only]
26
+ only = case o
27
+ when Array
28
+ o
29
+ else
30
+ [o]
31
+ end.map {|e| e.to_s }
32
+ end
33
+
34
+ if o = options[:except]
35
+ except = case o
36
+ when Array
37
+ o
38
+ else
39
+ [o]
40
+ end.map {|e| e.to_s }
41
+ end
42
+
43
+ if o = options[:static]
44
+ o.each_pair {|k,v|
45
+ static[k.to_s] = v
46
+ }
47
+ end
48
+
49
+ if defined?(after_commit)
50
+ # Rails 3
51
+ m = :after_commit
52
+ else
53
+ # Rails 2
54
+ m = :after_save
55
+ end
56
+
57
+ __send__(m) do |record|
58
+ data = {}
59
+ record.attribute_names.each {|name|
60
+ name = name.to_s
61
+ if (!only || only.include?(name)) && (!except || !except.include?(name))
62
+ data[name] = record.read_attribute(name)
63
+ end
64
+ }
65
+ static.each_pair {|k,v|
66
+ data[k] = v
67
+ }
68
+ if time = data['updated_at'] && time.is_a?(Time)
69
+ data['time'] = time.to_i
70
+ data.delete('updated_at')
71
+ end
72
+ TreasureData.log(tag, data)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -2,7 +2,7 @@
2
2
  module TreasureData
3
3
  module Logger
4
4
 
5
- # TODO shutdown handler
5
+ # TODO shutdown handler (deadlock)
6
6
 
7
7
  class TreasureDataLogger < Fluent::Logger::LoggerBase
8
8
  def initialize(apikey, tag, auto_create_table)
@@ -1,7 +1,7 @@
1
1
  module TreasureData
2
2
  module Logger
3
3
 
4
- VERSION = '0.1.2'
4
+ VERSION = '0.2.0'
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: 31
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
8
  - 2
10
- version: 0.1.2
9
+ - 0
10
+ version: 0.2.0
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-08-21 00:00:00 +09:00
18
+ date: 2011-08-28 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -78,6 +78,11 @@ extra_rdoc_files:
78
78
  files:
79
79
  - lib/td-logger.rb
80
80
  - lib/td/logger.rb
81
+ - lib/td/logger/agent/access_log.rb
82
+ - lib/td/logger/agent/middleware.rb
83
+ - lib/td/logger/agent/rails.rb
84
+ - lib/td/logger/agent/rails/controller.rb
85
+ - lib/td/logger/agent/rails/model.rb
81
86
  - lib/td/logger/tdlog.rb
82
87
  - lib/td/logger/version.rb
83
88
  - ChangeLog