mirror of
https://github.com/elastic/logstash.git
synced 2025-04-24 06:37:19 -04:00
support injectable Ruby logger in Java event and related specs
This commit is contained in:
parent
d6a9627f54
commit
29ea7f495b
5 changed files with 117 additions and 23 deletions
|
@ -135,4 +135,54 @@ describe LogStash::Event do
|
|||
expect(event["tags"]).to eq(["foo"])
|
||||
end
|
||||
end
|
||||
|
||||
module DummyLogger
|
||||
def self.warn(message)
|
||||
# do nothing
|
||||
end
|
||||
end
|
||||
|
||||
context "logger" do
|
||||
|
||||
let(:logger) { double("Logger") }
|
||||
after(:each) { LogStash::Event.logger = nil }
|
||||
|
||||
it "should set logger using a module" do
|
||||
LogStash::Event.logger = DummyLogger
|
||||
expect(DummyLogger).to receive(:warn).once
|
||||
LogStash::Event.new(TIMESTAMP => "invalid timestamp")
|
||||
end
|
||||
|
||||
it "should set logger using a mock" do
|
||||
LogStash::Event.logger = logger
|
||||
expect(logger).to receive(:warn)
|
||||
LogStash::Event.new(TIMESTAMP => "invalid timestamp")
|
||||
end
|
||||
|
||||
it "should unset logger" do
|
||||
# first set
|
||||
LogStash::Event.logger = logger
|
||||
expect(logger).to receive(:warn).once
|
||||
LogStash::Event.new(TIMESTAMP => "invalid timestamp")
|
||||
|
||||
# then unset
|
||||
LogStash::Event.logger = nil
|
||||
expect(logger).to receive(:warn).never
|
||||
# this will produce a log line in stdout by the Java Event
|
||||
LogStash::Event.new(TIMESTAMP => "ignore this log")
|
||||
end
|
||||
|
||||
|
||||
it "should warn on parsing errort" do
|
||||
LogStash::Event.logger = logger
|
||||
expect(logger).to receive(:warn).once.with(/^Error parsing/)
|
||||
LogStash::Event.new(TIMESTAMP => "invalid timestamp")
|
||||
end
|
||||
|
||||
it "should warn on invalid timestamp object" do
|
||||
LogStash::Event.logger = logger
|
||||
expect(logger).to receive(:warn).once.with(/^Unrecognized/)
|
||||
LogStash::Event.new(TIMESTAMP => Object.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,9 +28,9 @@ public class Event implements Cloneable, Serializable {
|
|||
public static final String VERSION = "@version";
|
||||
public static final String VERSION_ONE = "1";
|
||||
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
// TODO: add metadata support
|
||||
private static final Logger DEFAULT_LOGGER = new StdioLogger();
|
||||
private transient final ObjectMapper mapper = new ObjectMapper();
|
||||
private transient static Logger logger = DEFAULT_LOGGER;
|
||||
|
||||
public Event()
|
||||
{
|
||||
|
@ -225,18 +225,16 @@ public class Event implements Cloneable, Serializable {
|
|||
} else if (o instanceof RubySymbol) {
|
||||
return new Timestamp(((RubySymbol) o).asJavaString());
|
||||
} else {
|
||||
// TODO: add logging
|
||||
//return Timestamp.now();
|
||||
throw new IllegalArgumentException();
|
||||
Event.logger.warn("Unrecognized " + TIMESTAMP + " value type=" + o.getClass().toString());
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO: add error logging
|
||||
tag(TIMESTAMP_FAILURE_TAG);
|
||||
|
||||
this.data.put(TIMESTAMP_FAILURE_FIELD, o);
|
||||
|
||||
return Timestamp.now();
|
||||
Event.logger.warn("Error parsing " + TIMESTAMP + " string value=" + o.toString());
|
||||
}
|
||||
|
||||
tag(TIMESTAMP_FAILURE_TAG);
|
||||
this.data.put(TIMESTAMP_FAILURE_FIELD, o);
|
||||
|
||||
return Timestamp.now();
|
||||
}
|
||||
|
||||
public void tag(String tag) {
|
||||
|
@ -250,4 +248,8 @@ public class Event implements Cloneable, Serializable {
|
|||
tags.add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setLogger(Logger logger) {
|
||||
Event.logger = (logger == null) ? DEFAULT_LOGGER : logger;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.logstash;
|
||||
|
||||
// minimalist Logger interface to wire a logger callback in the Event class
|
||||
// for now only warn is defined because this is the only method that's required
|
||||
// in the Event class.
|
||||
// TODO: (colin) generalize this
|
||||
|
||||
public interface Logger {
|
||||
|
||||
// TODO: (colin) complete interface beyond warn when needed
|
||||
|
||||
void warn(String message);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.logstash;
|
||||
|
||||
public class StdioLogger implements Logger {
|
||||
|
||||
// TODO: (colin) complete implementation beyond warn when needed
|
||||
|
||||
public void warn(String message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,10 @@
|
|||
package com.logstash.ext;
|
||||
|
||||
import com.logstash.Event;
|
||||
import com.logstash.PathCache;
|
||||
import com.logstash.RubyToJavaConverter;
|
||||
import com.logstash.Timestamp;
|
||||
import com.logstash.*;
|
||||
import org.jruby.*;
|
||||
import org.jruby.anno.JRubyClass;
|
||||
import org.jruby.anno.JRubyConstant;
|
||||
import org.jruby.anno.JRubyMethod;
|
||||
import org.jruby.exceptions.RaiseException;
|
||||
import org.jruby.java.proxies.MapJavaProxy;
|
||||
import org.jruby.javasupport.JavaUtil;
|
||||
import org.jruby.runtime.Arity;
|
||||
import org.jruby.runtime.ObjectAllocator;
|
||||
|
@ -25,13 +20,13 @@ public class JrubyEventExtLibrary implements Library {
|
|||
|
||||
public void load(Ruby runtime, boolean wrap) throws IOException {
|
||||
RubyModule module = runtime.defineModule("LogStash");
|
||||
|
||||
RubyClass clazz = runtime.defineClassUnder("Event", runtime.getObject(), new ObjectAllocator() {
|
||||
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
|
||||
return new RubyEvent(runtime, rubyClass);
|
||||
}
|
||||
}, module);
|
||||
clazz.setConstant("LOGGER", runtime.getModule("Cabin").getClass("Channel")
|
||||
.callMethod("get", runtime.getModule("LogStash")));
|
||||
|
||||
clazz.setConstant("TIMESTAMP", runtime.newString(Event.TIMESTAMP));
|
||||
clazz.setConstant("TIMESTAMP_FAILURE_TAG", runtime.newString(Event.TIMESTAMP_FAILURE_TAG));
|
||||
clazz.setConstant("TIMESTAMP_FAILURE_FIELD", runtime.newString(Event.TIMESTAMP_FAILURE_FIELD));
|
||||
|
@ -39,9 +34,24 @@ public class JrubyEventExtLibrary implements Library {
|
|||
clazz.defineAnnotatedConstants(RubyEvent.class);
|
||||
}
|
||||
|
||||
public static class ProxyLogger implements Logger {
|
||||
private RubyObject logger;
|
||||
|
||||
public ProxyLogger(RubyObject logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
// TODO: (colin) complete implementation beyond warn when needed
|
||||
|
||||
public void warn(String message) {
|
||||
logger.callMethod("warn", RubyString.newString(logger.getRuntime(), message));
|
||||
}
|
||||
}
|
||||
|
||||
@JRubyClass(name = "Event", parent = "Object")
|
||||
public static class RubyEvent extends RubyObject {
|
||||
private Event event;
|
||||
private static RubyObject logger;
|
||||
|
||||
public RubyEvent(Ruby runtime, RubyClass klass) {
|
||||
super(runtime, klass);
|
||||
|
@ -206,9 +216,11 @@ public class JrubyEventExtLibrary implements Library {
|
|||
try {
|
||||
return RubyString.newString(context.runtime, event.sprintf(format.toString()));
|
||||
} catch (IOException e) {
|
||||
throw new RaiseException(getRuntime(),
|
||||
(RubyClass) getRuntime().getModule("LogStash").getClass("Error"),
|
||||
"timestamp field is missing", true);
|
||||
throw new RaiseException(
|
||||
getRuntime(),
|
||||
(RubyClass) getRuntime().getModule("LogStash").getClass("Error"),
|
||||
"timestamp field is missing", true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,5 +286,12 @@ public class JrubyEventExtLibrary implements Library {
|
|||
public IRubyObject ruby_timestamp(ThreadContext context) throws IOException {
|
||||
return new JrubyTimestampExtLibrary.RubyTimestamp(context.getRuntime(), this.event.getTimestamp());
|
||||
}
|
||||
|
||||
@JRubyMethod(name = "logger=", required = 1, meta = true)
|
||||
public static IRubyObject ruby_set_logger(ThreadContext context, IRubyObject recv, IRubyObject value)
|
||||
{
|
||||
Event.setLogger(value.isNil() ? null : new ProxyLogger((RubyObject)value));
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue