norikra 1.1.2-java → 1.2.0-java
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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Changes.md +4 -0
- data/Gemfile +4 -0
- data/README.md +3 -6
- data/lib/norikra/cli.rb +54 -54
- data/lib/norikra/engine.rb +91 -44
- data/lib/norikra/field.rb +12 -7
- data/lib/norikra/fieldset.rb +26 -13
- data/lib/norikra/listener.rb +192 -61
- data/lib/norikra/logger.rb +34 -10
- data/lib/norikra/output_pool.rb +1 -1
- data/lib/norikra/query/ast.rb +240 -20
- data/lib/norikra/query.rb +103 -46
- data/lib/norikra/rpc/handler.rb +3 -3
- data/lib/norikra/rpc/http.rb +1 -1
- data/lib/norikra/server.rb +34 -28
- data/lib/norikra/stats.rb +3 -3
- data/lib/norikra/target.rb +1 -1
- data/lib/norikra/typedef.rb +22 -17
- data/lib/norikra/typedef_manager.rb +9 -6
- data/lib/norikra/udf.rb +6 -2
- data/lib/norikra/version.rb +1 -1
- data/lib/norikra/webui/api.rb +3 -3
- data/lib/norikra/webui/handler.rb +6 -6
- data/norikra.gemspec +0 -1
- data/script/{spec_server_pry → pry} +0 -24
- data/spec/field_spec.rb +14 -0
- data/spec/fieldset_spec.rb +111 -0
- data/spec/listener_spec.rb +64 -26
- data/spec/query_spec.rb +171 -25
- data/spec/spec_helper.rb +0 -46
- data/spec/typedef_manager_spec.rb +15 -9
- data/spec/typedef_spec.rb +11 -11
- metadata +3 -19
- data/lib/norikra/rpc/error.rb +0 -0
- data/lib/norikra/rubyudf.rb +0 -49
data/lib/norikra/field.rb
CHANGED
@@ -35,7 +35,7 @@ module Norikra
|
|
35
35
|
### expected java.lang.Class or java.util.Map or the name of a previously-declared Map or ObjectArray type
|
36
36
|
#### Correct type name is 'int'. see and run 'junks/esper-test.rb'
|
37
37
|
|
38
|
-
attr_accessor :name, :type, :esper_type, :optional, :escaped_name, :container_name, :container_type
|
38
|
+
attr_accessor :name, :type, :esper_type, :optional, :nullable, :escaped_name, :container_name, :container_type
|
39
39
|
|
40
40
|
def self.esper_type_map(type)
|
41
41
|
case type.to_s.downcase
|
@@ -75,10 +75,11 @@ module Norikra
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
def initialize(name, type, optional=nil)
|
78
|
+
def initialize(name, type, optional=nil, nullable=false)
|
79
79
|
@name = name.to_s
|
80
80
|
@type = self.class.valid_type(type)
|
81
81
|
@optional = optional
|
82
|
+
@nullable = nullable
|
82
83
|
|
83
84
|
@escaped_name = self.class.escape_name(@name)
|
84
85
|
|
@@ -154,24 +155,28 @@ module Norikra
|
|
154
155
|
|
155
156
|
def to_hash(sym=false)
|
156
157
|
if sym
|
157
|
-
{name: @name, type: @type, optional: @optional}
|
158
|
+
{name: @name, type: @type, optional: @optional, nullable: @nullable}
|
158
159
|
else
|
159
|
-
{'name' => @name, 'type' => @type, 'optional' => @optional}
|
160
|
+
{'name' => @name, 'type' => @type, 'optional' => @optional, 'nullable' => @nullable}
|
160
161
|
end
|
161
162
|
end
|
162
163
|
|
163
164
|
def dup(optional=nil)
|
164
|
-
self.class.new(@name, @type, optional.nil? ? @optional : optional)
|
165
|
+
self.class.new(@name, @type, optional.nil? ? @optional : optional, @nullable)
|
165
166
|
end
|
166
167
|
|
167
168
|
def ==(other)
|
168
|
-
self.name == other.name && self.type == other.type && self.optional == other.optional
|
169
|
+
self.name == other.name && self.type == other.type && self.optional == other.optional && self.nullable == other.nullable
|
169
170
|
end
|
170
171
|
|
171
172
|
def optional? # used outside of FieldSet
|
172
173
|
@optional
|
173
174
|
end
|
174
175
|
|
176
|
+
def nullable?
|
177
|
+
@nullable
|
178
|
+
end
|
179
|
+
|
175
180
|
# def value(event) # by define_value_accessor
|
176
181
|
|
177
182
|
def format(value, element_path=nil) #element_path ex: 'fname.fchild', 'fname.$0', 'f.fchild.$2'
|
@@ -228,7 +233,7 @@ module Norikra
|
|
228
233
|
self.instance_eval do
|
229
234
|
def safe_fetch(v, accessor)
|
230
235
|
unless accessor.is_a?(String) || accessor.is_a?(Fixnum)
|
231
|
-
raise ArgumentError, "container_accessor must be a String or Interger, but #{accessor.class.to_s}"
|
236
|
+
raise ::ArgumentError, "container_accessor must be a String or Interger, but #{accessor.class.to_s}"
|
232
237
|
end
|
233
238
|
if v.is_a?(Hash)
|
234
239
|
# v[accessor] || v[accessor.to_s]
|
data/lib/norikra/fieldset.rb
CHANGED
@@ -17,11 +17,11 @@ module Norikra
|
|
17
17
|
elsif data.is_a?(Hash)
|
18
18
|
type = data[:type].to_s
|
19
19
|
optional = data.has_key?(:optional) ? data[:optional] : default_optional
|
20
|
-
@fields[key.to_s] = Field.new(key.to_s, type, optional)
|
20
|
+
@fields[key.to_s] = Field.new(key.to_s, type, optional, !!data[:nullable])
|
21
21
|
elsif data.is_a?(String) || data.is_a?(Symbol)
|
22
22
|
@fields[key.to_s] = Field.new(key.to_s, data.to_s, default_optional)
|
23
23
|
else
|
24
|
-
raise ArgumentError, "FieldSet.new argument class unknown: #{fields.class}"
|
24
|
+
raise ::ArgumentError, "FieldSet.new argument class unknown: #{fields.class}"
|
25
25
|
end
|
26
26
|
end
|
27
27
|
self.update_summary
|
@@ -34,7 +34,7 @@ module Norikra
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def dup
|
37
|
-
fields = Hash[@fields.map{|key,field| [key, {:
|
37
|
+
fields = Hash[@fields.map{|key,field| [key, {type: field.type, optional: field.optional, nullable: field.nullable?}]}]
|
38
38
|
self.class.new(fields, nil, @rebounds, @query_unique_keys)
|
39
39
|
end
|
40
40
|
|
@@ -75,13 +75,16 @@ module Norikra
|
|
75
75
|
dig.call(container)
|
76
76
|
end
|
77
77
|
|
78
|
+
#### field_names_key is for lookup FieldSet from event data
|
79
|
+
# field_names_key: a,b,c,d
|
80
|
+
### comma separated field names, which contains valid values (null fields are not included)
|
78
81
|
def self.field_names_key(data, fieldset=nil, strict=false, additional_fields=[])
|
79
82
|
if !fieldset && strict
|
80
83
|
raise RuntimeError, "strict(true) cannot be specified with fieldset=nil"
|
81
84
|
end
|
82
85
|
|
83
86
|
unless fieldset
|
84
|
-
return data.keys.sort.join(',')
|
87
|
+
return data.reject{|k,v| v.respond_to?(:nullable?) && v.nullable? }.keys.sort.join(',')
|
85
88
|
end
|
86
89
|
|
87
90
|
keys = []
|
@@ -113,8 +116,9 @@ module Norikra
|
|
113
116
|
self.class.field_names_key(@fields)
|
114
117
|
end
|
115
118
|
|
119
|
+
# summary is for checks whether FieldSet is already registered or not
|
116
120
|
def update_summary
|
117
|
-
@summary = @fields.keys.sort.map{|k| @fields[k].escaped_name + ':'
|
121
|
+
@summary = @fields.keys.sort.map{|k| f = @fields[k]; "#{f.escaped_name}:#{f.type}" + (f.nullable? ? ':nullable' : '')}.join(',')
|
118
122
|
self
|
119
123
|
end
|
120
124
|
|
@@ -125,7 +129,10 @@ module Norikra
|
|
125
129
|
self.update_summary
|
126
130
|
end
|
127
131
|
|
128
|
-
|
132
|
+
def nullable_diff(fieldset) # data_fieldset.nullable_diff(query_fieldset)
|
133
|
+
fieldset.fields.select{|fname, f| !self.fields[fname] && f.nullable? }.values
|
134
|
+
end
|
135
|
+
|
129
136
|
def ==(other)
|
130
137
|
return false if self.class != other.class
|
131
138
|
self.summary == other.summary && self.query_unique_keys == other.query_unique_keys
|
@@ -139,15 +146,16 @@ module Norikra
|
|
139
146
|
d
|
140
147
|
end
|
141
148
|
|
142
|
-
def subset?(other) # self is subset of other (or not)
|
143
|
-
|
149
|
+
def subset?(other) # self is subset of other (or not) ### query_fieldset.subset?(fieldset_referred_from_event_data)
|
150
|
+
### nullable fields can be ignored (to be updated later, with nullable fields ignored here)
|
151
|
+
(self.fields.keys - other.fields.keys).reject{|fname| @fields[fname].nullable? }.size < 1
|
144
152
|
end
|
145
153
|
|
146
154
|
def event_type_name
|
147
155
|
@event_type_name.dup
|
148
156
|
end
|
149
157
|
|
150
|
-
def bind(target, level,
|
158
|
+
def bind(target, level, type_name_update=false)
|
151
159
|
@target = target
|
152
160
|
@level = level
|
153
161
|
prefix = case level
|
@@ -155,17 +163,22 @@ module Norikra
|
|
155
163
|
when :query then 'q_'
|
156
164
|
when :data then 'e_' # event
|
157
165
|
else
|
158
|
-
raise ArgumentError, "unknown fieldset bind level: #{level}, for target #{target}"
|
166
|
+
raise ::ArgumentError, "unknown fieldset bind level: #{level}, for target #{target}"
|
159
167
|
end
|
160
|
-
@rebounds += 1 if
|
168
|
+
@rebounds += 1 if type_name_update
|
161
169
|
query_unique_key = @query_unique_keys ? @query_unique_keys.join("\t") : ''
|
162
170
|
|
163
171
|
@event_type_name = prefix + Digest::MD5.hexdigest([target, level.to_s, @rebounds.to_s, query_unique_key, @summary].join("\t"))
|
164
172
|
self
|
165
173
|
end
|
166
174
|
|
167
|
-
def rebind(
|
168
|
-
self.dup
|
175
|
+
def rebind(type_name_update, query_fieldset=nil)
|
176
|
+
renew = self.dup
|
177
|
+
if query_fieldset
|
178
|
+
diff = self.nullable_diff(query_fieldset)
|
179
|
+
renew.update(diff, true) unless diff.empty? # all nullable fields are optional
|
180
|
+
end
|
181
|
+
renew.bind(@target, @level, type_name_update)
|
169
182
|
end
|
170
183
|
|
171
184
|
def format(data)
|
data/lib/norikra/listener.rb
CHANGED
@@ -4,90 +4,221 @@ require 'esper/lib/commons-logging-1.1.3.jar'
|
|
4
4
|
require 'esper/lib/antlr-runtime-4.1.jar'
|
5
5
|
require 'esper/lib/cglib-nodep-3.1.jar'
|
6
6
|
|
7
|
+
require 'rubygems'
|
8
|
+
|
7
9
|
require 'norikra/field'
|
8
10
|
require 'norikra/query'
|
9
11
|
|
12
|
+
require 'norikra/logger'
|
13
|
+
include Norikra::Log
|
14
|
+
|
10
15
|
require 'json'
|
11
16
|
|
12
17
|
module Norikra
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
module Listener
|
19
|
+
def self.listup
|
20
|
+
return unless defined? Gem
|
21
|
+
|
22
|
+
plugins = Gem.find_latest_files('norikra/listener/*.rb')
|
23
|
+
plugins.each do |plugin|
|
24
|
+
begin
|
25
|
+
debug "plugin file found!", file: plugin
|
26
|
+
rbpath = plugin.dup
|
27
|
+
4.times do
|
28
|
+
rbpath = File.dirname( rbpath )
|
29
|
+
end
|
30
|
+
files = Dir.entries( rbpath )
|
31
|
+
gemname = files.select{|f| f=~ /\.gemspec$/ }.first.sub(/\.gemspec$/, '')
|
32
|
+
trace "Loading listener gem", gemname: gemname, path: plugin
|
33
|
+
require gemname
|
34
|
+
load plugin
|
35
|
+
rescue => e
|
36
|
+
warn "Failed to load norikra listener plugin", plugin: plugin.to_s, error_class: e.class, error: e.message
|
37
|
+
e.backtrace.each do |t|
|
38
|
+
warn " " + t
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
known_consts = [:Base, :MemoryPool, :Loopback, :Stdout]
|
44
|
+
listeners = [Norikra::Listener::Stdout, Norikra::Listener::Loopback]
|
45
|
+
self.constants.each do |c|
|
46
|
+
next if known_consts.include?(c)
|
47
|
+
|
48
|
+
klass = Norikra::Listener.const_get(c)
|
49
|
+
if klass.is_a?(Class) && klass.superclass == Norikra::Listener::Base
|
50
|
+
listeners.push(klass)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
listeners.push(Norikra::Listener::MemoryPool)
|
54
|
+
listeners
|
21
55
|
end
|
22
56
|
|
23
|
-
|
24
|
-
|
25
|
-
|
57
|
+
class Base
|
58
|
+
include com.espertech.esper.client.UpdateListener
|
59
|
+
|
60
|
+
DEFAULT_ASYNC_INTERVAL = 0.1
|
61
|
+
|
62
|
+
def self.check(group_name)
|
63
|
+
raise NotImplementedError
|
26
64
|
end
|
27
65
|
|
28
|
-
|
66
|
+
def initialize(query_name, query_group, events_statistics)
|
67
|
+
@query_name = query_name
|
68
|
+
@query_group = query_group
|
69
|
+
@events_statistics = events_statistics
|
29
70
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
elsif value.respond_to?(:force_encoding)
|
37
|
-
value.force_encoding('UTF-8')
|
38
|
-
else
|
39
|
-
value
|
71
|
+
@async_interval = DEFAULT_ASYNC_INTERVAL
|
72
|
+
|
73
|
+
@thread = nil
|
74
|
+
@events = []
|
75
|
+
@mutex = Mutex.new
|
76
|
+
@running = true
|
40
77
|
end
|
41
|
-
end
|
42
78
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
@
|
49
|
-
|
50
|
-
|
79
|
+
# def engine=(engine)
|
80
|
+
# @engine = engine
|
81
|
+
# end
|
82
|
+
|
83
|
+
# def output_pool=(output_pool)
|
84
|
+
# @output_pool = output_pool
|
85
|
+
# end
|
86
|
+
|
87
|
+
def start
|
88
|
+
if self.respond_to?(:process_async)
|
89
|
+
trace "starting thread to process events in background", query: @query_name
|
90
|
+
@thread = Thread.new(&method(:background))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def background
|
95
|
+
trace "backgroupd thread starts", query: @query_name
|
96
|
+
while @running
|
97
|
+
events_empty = true
|
98
|
+
events = nil
|
99
|
+
@mutex.synchronize do
|
100
|
+
events = @events
|
101
|
+
@events = []
|
102
|
+
end
|
103
|
+
unless events.empty?
|
104
|
+
events_empty = false
|
105
|
+
trace("calling #process_async"){ {listener: self.class, query: @query_name, events: events.size} }
|
106
|
+
process_async(events)
|
107
|
+
end
|
108
|
+
sleep @async_interval if events_empty
|
109
|
+
end
|
110
|
+
rescue => e
|
111
|
+
error "exception in listener background thread, stopped", listener: self.class, query: @query_name, error: e
|
112
|
+
end
|
113
|
+
|
114
|
+
def push(events)
|
115
|
+
@mutex.synchronize do
|
116
|
+
@events += events
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# def process_async
|
121
|
+
# end
|
51
122
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
123
|
+
def shutdown
|
124
|
+
trace "stopping listener", query: @query_name
|
125
|
+
@running = false
|
126
|
+
@thread.join if @thread
|
127
|
+
@thread = nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def type_convert(value)
|
131
|
+
if value.respond_to?(:getUnderlying)
|
132
|
+
value = value.getUnderlying
|
133
|
+
end
|
134
|
+
|
135
|
+
trace("converting"){ { value: value } }
|
136
|
+
|
137
|
+
if value.nil?
|
138
|
+
value
|
139
|
+
elsif value.respond_to?(:to_hash)
|
140
|
+
Hash[ value.to_hash.map{|k,v| [ Norikra::Field.unescape_name(k), type_convert(v)] } ]
|
141
|
+
elsif value.respond_to?(:to_a)
|
142
|
+
value.to_a.map{|v| type_convert(v) }
|
143
|
+
elsif value.respond_to?(:force_encoding)
|
144
|
+
value.force_encoding('UTF-8')
|
145
|
+
else
|
146
|
+
value
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def update(new_events, old_events)
|
151
|
+
t = Time.now.to_i
|
152
|
+
events = new_events.map{|e| [t, type_convert(e)]}
|
153
|
+
trace("updated event"){ { query: @query_name, group: @query_group, event: events } }
|
154
|
+
push(events)
|
155
|
+
@events_statistics[:output] += events.size
|
156
|
+
end
|
59
157
|
end
|
60
158
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
159
|
+
class MemoryPool < Base
|
160
|
+
def self.check(group_name)
|
161
|
+
true
|
162
|
+
end
|
163
|
+
|
164
|
+
def output_pool=(output_pool)
|
165
|
+
@output_pool = output_pool
|
166
|
+
end
|
167
|
+
|
168
|
+
def update(new_events, old_events)
|
169
|
+
t = Time.now.to_i
|
170
|
+
events = new_events.map{|e| [t, type_convert(e)]}
|
171
|
+
trace("updated event"){ { query: @query_name, group: @query_group, event: events } }
|
172
|
+
@output_pool.push(@query_name, @query_group, events)
|
173
|
+
@events_statistics[:output] += events.size
|
174
|
+
end
|
69
175
|
end
|
70
|
-
end
|
71
176
|
|
72
|
-
|
73
|
-
|
74
|
-
|
177
|
+
class Loopback < Base
|
178
|
+
def self.check(group_name)
|
179
|
+
group_name && group_name =~ /^LOOPBACK\((.+)\)$/ && $1
|
180
|
+
end
|
75
181
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
182
|
+
def initialize(query_name, query_group, events_statistics)
|
183
|
+
super
|
184
|
+
@loopback_target = Loopback.check(query_group)
|
185
|
+
raise "BUG: query group is not 'LOOPBACK(...)'" unless @loopback_target
|
186
|
+
end
|
187
|
+
|
188
|
+
def engine=(engine)
|
189
|
+
@engine = engine
|
190
|
+
end
|
80
191
|
|
81
|
-
|
192
|
+
def update(new_events, old_events)
|
193
|
+
event_list = new_events.map{|e| type_convert(e) }
|
194
|
+
trace("loopback event"){ { query: @query_name, group: @query_group, event: event_list } }
|
195
|
+
@events_statistics[:output] += event_list.size
|
196
|
+
#
|
197
|
+
# We does NOT convert 'container.$0' into container['field'].
|
198
|
+
# Use escaped names like 'container__0'. That is NOT so confused.
|
199
|
+
@engine.send(@loopback_target, event_list)
|
200
|
+
end
|
82
201
|
end
|
83
202
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
203
|
+
class Stdout < Base
|
204
|
+
def self.check(group_name)
|
205
|
+
group_name && group_name == "STDOUT()"
|
206
|
+
end
|
207
|
+
|
208
|
+
def initialize(query_name, query_group, events_statistics)
|
209
|
+
super
|
210
|
+
raise "BUG: query group is not 'STDOUT()'" unless Stdout.check(query_group)
|
211
|
+
@stdout = STDOUT
|
212
|
+
end
|
213
|
+
|
214
|
+
def update(new_events, old_events)
|
215
|
+
event_list = new_events.map{|e| type_convert(e) }
|
216
|
+
trace("stdout event"){ { query: @query_name, event: event_list } }
|
217
|
+
@events_statistics[:output] += event_list.size
|
88
218
|
|
89
|
-
|
90
|
-
|
219
|
+
event_list.each do |e|
|
220
|
+
@stdout.puts @query_name + "\t" + JSON.dump(e)
|
221
|
+
end
|
91
222
|
end
|
92
223
|
end
|
93
224
|
end
|
data/lib/norikra/logger.rb
CHANGED
@@ -55,7 +55,7 @@ module Norikra
|
|
55
55
|
end
|
56
56
|
|
57
57
|
level = level.upcase
|
58
|
-
raise ArgumentError, "unknown log level: #{level}" unless LOG_LEVELS.include?(level)
|
58
|
+
raise ::ArgumentError, "unknown log level: #{level}" unless LOG_LEVELS.include?(level)
|
59
59
|
|
60
60
|
p = java.util.Properties.new
|
61
61
|
p.setProperty('log4j.appender.default.layout', 'org.apache.log4j.PatternLayout')
|
@@ -122,32 +122,44 @@ module Norikra
|
|
122
122
|
|
123
123
|
def self.logger; @@logger ; end
|
124
124
|
|
125
|
-
def trace(message, data=nil)
|
125
|
+
def trace(message, data=nil, &block)
|
126
|
+
return unless @@logger.enabled?(LEVEL_TRACE)
|
127
|
+
data ||= block
|
126
128
|
from = @@devmode ? caller_locations(1,1) : nil
|
127
129
|
@@logger.trace(message, data, from)
|
128
130
|
end
|
129
131
|
|
130
|
-
def debug(message, data=nil)
|
132
|
+
def debug(message, data=nil, &block)
|
133
|
+
return unless @@logger.enabled?(LEVEL_DEBUG)
|
134
|
+
data ||= block
|
131
135
|
from = @@devmode ? caller_locations(1,1) : nil
|
132
136
|
@@logger.debug(message, data, from)
|
133
137
|
end
|
134
138
|
|
135
|
-
def info(message, data=nil)
|
139
|
+
def info(message, data=nil, &block)
|
140
|
+
return unless @@logger.enabled?(LEVEL_INFO)
|
141
|
+
data ||= block
|
136
142
|
from = @@devmode ? caller_locations(1,1) : nil
|
137
143
|
@@logger.info(message, data, from)
|
138
144
|
end
|
139
145
|
|
140
|
-
def warn(message, data=nil)
|
146
|
+
def warn(message, data=nil, &block)
|
147
|
+
return unless @@logger.enabled?(LEVEL_WARN)
|
148
|
+
data ||= block
|
141
149
|
from = @@devmode ? caller_locations(1,1) : nil
|
142
150
|
@@logger.warn(message, data, from)
|
143
151
|
end
|
144
152
|
|
145
|
-
def error(message, data=nil)
|
153
|
+
def error(message, data=nil, &block)
|
154
|
+
return unless @@logger.enabled?(LEVEL_ERROR)
|
155
|
+
data ||= block
|
146
156
|
from = @@devmode ? caller_locations(1,1) : nil
|
147
157
|
@@logger.error(message, data, from)
|
148
158
|
end
|
149
159
|
|
150
|
-
def fatal(message, data=nil)
|
160
|
+
def fatal(message, data=nil, &block)
|
161
|
+
# always enabled
|
162
|
+
data ||= block
|
151
163
|
from = @@devmode ? caller_locations(1,1) : nil
|
152
164
|
@@logger.fatal(message, data, from)
|
153
165
|
end
|
@@ -172,6 +184,17 @@ module Norikra
|
|
172
184
|
@buffer << [Time.now.strftime(TIME_FORMAT), level, line]
|
173
185
|
end
|
174
186
|
|
187
|
+
def enabled?(level)
|
188
|
+
case level
|
189
|
+
when LEVEL_TRACE then @log4j.isTraceEnabled
|
190
|
+
when LEVEL_DEBUG then @log4j.isDebugEnabled
|
191
|
+
when LEVEL_INFO then @log4j.isInfoEnabled
|
192
|
+
when LEVEL_WARN then @log4j.isWarnEnabled
|
193
|
+
when LEVEL_ERROR then @log4j.isErrorEnabled
|
194
|
+
else true
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
175
198
|
def trace(message, data=nil, from=nil)
|
176
199
|
return unless @log4j.isTraceEnabled
|
177
200
|
line = format(from, message, data)
|
@@ -225,7 +248,7 @@ module Norikra
|
|
225
248
|
|
226
249
|
#, status:404, message:'content not found'
|
227
250
|
if data.is_a?(Proc)
|
228
|
-
|
251
|
+
format_data(data.call)
|
229
252
|
elsif data.is_a?(Hash)
|
230
253
|
', ' + data.map{|k,v| "#{k}:#{v.inspect}"}.join(', ')
|
231
254
|
else
|
@@ -245,14 +268,15 @@ module Norikra
|
|
245
268
|
FORMAT_SIMULATED = "%s [%s] %s\n"
|
246
269
|
attr_accessor :logs, :output
|
247
270
|
def initialize
|
248
|
-
@logs = { :
|
271
|
+
@logs = { TRACE: [], DEBUG: [], INFO: [], WARN: [], ERROR: [], FATAL: [] }
|
249
272
|
@output = []
|
250
273
|
end
|
251
274
|
def log(level, message, data, from)
|
252
|
-
@logs[level].push({:
|
275
|
+
@logs[level].push({message: message, data: data, from: from})
|
253
276
|
formatted = sprintf(FORMAT_SIMULATED, Time.now.strftime(TIME_FORMAT), level.to_s, format(from, message, data))
|
254
277
|
@output.push(formatted)
|
255
278
|
end
|
279
|
+
def enabled?(level); true; end
|
256
280
|
def trace(m,d,f); self.log(:TRACE,m,d,f); end
|
257
281
|
def debug(m,d,f); self.log(:DEBUG,m,d,f); end
|
258
282
|
def info(m,d,f) ; self.log(:INFO, m,d,f); end
|