Skip to content

Commit dbfe349

Browse files
wiibaaPere Urbon-Bayes
authored andcommitted
refactoring to allows unit testing of logstash event creation
1 parent 6a2b787 commit dbfe349

File tree

2 files changed

+78
-29
lines changed

2 files changed

+78
-29
lines changed

lib/logstash/inputs/log4j.rb

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -59,41 +59,45 @@ def register
5959
@logger.info("Log4j input")
6060
end # def register
6161

62+
public
63+
def create_event(log4j_obj)
64+
# NOTE: log4j_obj is org.apache.log4j.spi.LoggingEvent
65+
event = LogStash::Event.new("message" => log4j_obj.getRenderedMessage)
66+
event["path"] = log4j_obj.getLoggerName
67+
event["priority"] = log4j_obj.getLevel.toString
68+
event["logger_name"] = log4j_obj.getLoggerName
69+
event["thread"] = log4j_obj.getThreadName
70+
event["class"] = log4j_obj.getLocationInformation.getClassName
71+
event["file"] = log4j_obj.getLocationInformation.getFileName + ":" + log4j_obj.getLocationInformation.getLineNumber
72+
event["method"] = log4j_obj.getLocationInformation.getMethodName
73+
event["NDC"] = log4j_obj.getNDC if log4j_obj.getNDC
74+
event["stack_trace"] = log4j_obj.getThrowableStrRep.to_a.join("\n") if log4j_obj.getThrowableInformation
75+
76+
# Add the MDC context properties to event
77+
if log4j_obj.getProperties
78+
log4j_obj.getPropertyKeySet.each do |key|
79+
event[key] = log4j_obj.getProperty(key)
80+
end
81+
end
82+
return event
83+
end # def create_event
84+
6285
private
6386
def handle_socket(socket, output_queue)
6487
begin
6588
# JRubyObjectInputStream uses JRuby class path to find the class to de-serialize to
6689
ois = JRubyObjectInputStream.new(java.io.BufferedInputStream.new(socket.to_inputstream))
6790
loop do
68-
# NOTE: log4j_obj is org.apache.log4j.spi.LoggingEvent
69-
log4j_obj = ois.readObject
70-
event = LogStash::Event.new("message" => log4j_obj.getRenderedMessage)
71-
decorate(event)
91+
event = create_event(ois.readObject)
7292
event["host"] = socket.peer
73-
event["path"] = log4j_obj.getLoggerName
74-
event["priority"] = log4j_obj.getLevel.toString
75-
event["logger_name"] = log4j_obj.getLoggerName
76-
event["thread"] = log4j_obj.getThreadName
77-
event["class"] = log4j_obj.getLocationInformation.getClassName
78-
event["file"] = log4j_obj.getLocationInformation.getFileName + ":" + log4j_obj.getLocationInformation.getLineNumber
79-
event["method"] = log4j_obj.getLocationInformation.getMethodName
80-
event["NDC"] = log4j_obj.getNDC if log4j_obj.getNDC
81-
event["stack_trace"] = log4j_obj.getThrowableStrRep.to_a.join("\n") if log4j_obj.getThrowableInformation
82-
83-
# Add the MDC context properties to '@fields'
84-
if log4j_obj.getProperties
85-
log4j_obj.getPropertyKeySet.each do |key|
86-
event[key] = log4j_obj.getProperty(key)
87-
end
88-
end
89-
93+
decorate(event)
9094
output_queue << event
9195
end # loop do
9296
rescue => e
93-
@logger.debug("Closing connection", :client => socket.peer,
97+
@logger.debug? && @logger.debug("Closing connection", :client => socket.peer,
9498
:exception => e)
9599
rescue Timeout::Error
96-
@logger.debug("Closing connection after read timeout",
100+
@logger.debug? && @logger.debug("Closing connection after read timeout",
97101
:client => socket.peer)
98102
end # begin
99103
ensure
@@ -118,13 +122,9 @@ def readline(socket)
118122
def run(output_queue)
119123
if server?
120124
loop do
121-
# Start a new thread for each connection.
122125
Thread.start(@server_socket.accept) do |s|
123-
# TODO(sissel): put this block in its own method.
124-
125-
# monkeypatch a 'peer' method onto the socket.
126126
s.instance_eval { class << self; include ::LogStash::Util::SocketPeer end }
127-
@logger.debug("Accepted connection", :client => s.peer,
127+
@logger.debug? && @logger.debug("Accepted connection", :client => s.peer,
128128
:server => "#{@host}:#{@port}")
129129
handle_socket(s, output_queue)
130130
end # Thread.start
@@ -133,7 +133,7 @@ def run(output_queue)
133133
loop do
134134
client_socket = TCPSocket.new(@host, @port)
135135
client_socket.instance_eval { class << self; include ::LogStash::Util::SocketPeer end }
136-
@logger.debug("Opened connection", :client => "#{client_socket.peer}")
136+
@logger.debug? && @logger.debug("Opened connection", :client => "#{client_socket.peer}")
137137
handle_socket(client_socket, output_queue)
138138
end # loop
139139
end

spec/inputs/log4j_spec.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,53 @@
1010
# register will try to load jars and raise if it cannot find jars or if org.apache.log4j.spi.LoggingEvent class is not present
1111
expect {input.register}.to_not raise_error
1212
end
13+
14+
context "reading general information from a org.apache.log4j.spi.LoggingEvent" do
15+
let (:input) { LogStash::Plugin.lookup("input", "log4j").new("mode" => "client") }
16+
let (:log_obj) {
17+
org.apache.log4j.spi.LoggingEvent.new(
18+
"org.apache.log4j.Logger",
19+
org.apache.log4j.Logger.getLogger("org.apache.log4j.LayoutTest"),
20+
1426366971,
21+
org.apache.log4j.Level::INFO,
22+
"Hello, World",
23+
nil
24+
)
25+
}
26+
27+
let (:log_obj_with_stacktrace) {
28+
org.apache.log4j.spi.LoggingEvent.new(
29+
"org.apache.log4j.Logger",
30+
org.apache.log4j.Logger.getLogger("org.apache.log4j.LayoutTest"),
31+
1426366971,
32+
org.apache.log4j.Level::INFO,
33+
"Hello, World",
34+
java.lang.IllegalStateException.new()
35+
)
36+
}
37+
38+
it "creates event with general information" do
39+
subject = input.create_event(log_obj)
40+
expect(subject["path"]).to eq("org.apache.log4j.LayoutTest")
41+
expect(subject["priority"]).to eq("INFO")
42+
expect(subject["logger_name"]).to eq("org.apache.log4j.LayoutTest")
43+
expect(subject["thread"]).to eq("main")
44+
expect(subject["message"]).to eq("Hello, World")
45+
# checks locationInformation is collected, but testing exact values is not meaningful in jruby
46+
expect(subject["class"]).not_to be_empty
47+
expect(subject["file"]).not_to be_empty
48+
expect(subject["method"]).not_to be_empty
49+
end
50+
51+
it "creates event without stacktrace" do
52+
subject = input.create_event(log_obj)
53+
expect(subject["stack_trace"]).to be_nil
54+
end
55+
56+
it "creates event with stacktrace" do
57+
subject = input.create_event(log_obj_with_stacktrace)
58+
#checks stack_trace is collected, exact value is too monstruous
59+
expect(subject["stack_trace"]).not_to be_empty
60+
end
61+
end
1362
end

0 commit comments

Comments
 (0)