td-logger 0.1.2 → 0.2.0

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,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