-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add Event#from_json method #4631
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
# this is a generated file, to avoid over-writing it just delete this comment | ||
require 'jar_dependencies' | ||
|
||
require_jar( 'org.codehaus.jackson', 'jackson-core-asl', '1.9.13' ) | ||
require_jar( 'org.codehaus.jackson', 'jackson-mapper-asl', '1.9.13' ) | ||
require_jar( 'com.fasterxml.jackson.core', 'jackson-core', '2.7.1' ) | ||
require_jar( 'com.fasterxml.jackson.core', 'jackson-annotations', '2.7.0' ) | ||
require_jar( 'com.fasterxml.jackson.core', 'jackson-databind', '2.7.1-1' ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
package com.logstash; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.logstash.ext.JrubyTimestampExtLibrary; | ||
import org.codehaus.jackson.map.ObjectMapper; | ||
import org.joda.time.DateTime; | ||
import org.jruby.RubySymbol; | ||
|
||
|
@@ -153,10 +153,40 @@ public boolean includes(String reference) { | |
} | ||
} | ||
|
||
public String toJson() throws IOException { | ||
public String toJson() | ||
throws IOException | ||
{ | ||
return mapper.writeValueAsString((Map<String, Object>)this.data); | ||
} | ||
|
||
public static Event[] fromJson(String json) | ||
throws IOException | ||
{ | ||
Event[] result; | ||
|
||
if (json == null || json.trim().isEmpty()) { | ||
return new Event[]{ new Event() }; | ||
} | ||
|
||
Object o = mapper.readValue(json, Object.class); | ||
// we currently only support Map or Array json objects | ||
if (o instanceof Map) { | ||
result = new Event[]{ new Event((Map)o) }; | ||
} else if (o instanceof List) { | ||
result = new Event[((List) o).size()]; | ||
int i = 0; | ||
for (Object e : (List)o) { | ||
if (!(e instanceof Map)) { | ||
throw new IOException("incompatible inner json array object type=" + e.getClass().getName() + " , only hash map is suppoted"); | ||
} | ||
result[i++] = new Event((Map)e); | ||
} | ||
} else { | ||
throw new IOException("incompatible json object type=" + o.getClass().getName() + " , only hash map or arrays are suppoted"); | ||
} | ||
return result; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice to catch either "[1,2,3,4]" or ""fubar"", both valid JSON but useless to us. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yup, also added good test harness around these cases. |
||
public Map toMap() { | ||
return this.data; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
package com.logstash; | ||
|
||
import org.codehaus.jackson.JsonGenerationException; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,10 @@ | |
|
||
public class JrubyEventExtLibrary implements Library { | ||
|
||
private static RubyClass PARSER_ERROR = null; | ||
private static RubyClass GENERATOR_ERROR = null; | ||
private static RubyClass LOGSTASH_ERROR = null; | ||
|
||
public void load(Ruby runtime, boolean wrap) throws IOException { | ||
RubyModule module = runtime.defineModule("LogStash"); | ||
|
||
|
@@ -54,6 +58,19 @@ public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) { | |
clazz.setConstant("VERSION_ONE", runtime.newString(Event.VERSION_ONE)); | ||
clazz.defineAnnotatedMethods(RubyEvent.class); | ||
clazz.defineAnnotatedConstants(RubyEvent.class); | ||
|
||
PARSER_ERROR = runtime.getModule("LogStash").defineOrGetModuleUnder("Json").getClass("ParserError"); | ||
if (PARSER_ERROR == null) { | ||
throw new RaiseException(runtime, runtime.getClass("StandardError"), "Could not find LogStash::Json::ParserError class", true); | ||
} | ||
GENERATOR_ERROR = runtime.getModule("LogStash").defineOrGetModuleUnder("Json").getClass("GeneratorError"); | ||
if (GENERATOR_ERROR == null) { | ||
throw new RaiseException(runtime, runtime.getClass("StandardError"), "Could not find LogStash::Json::GeneratorError class", true); | ||
} | ||
LOGSTASH_ERROR = runtime.getModule("LogStash").getClass("Error"); | ||
if (LOGSTASH_ERROR == null) { | ||
throw new RaiseException(runtime, runtime.getClass("StandardError"), "Could not find LogStash::Error class", true); | ||
} | ||
} | ||
|
||
public static class ProxyLogger implements Logger { | ||
|
@@ -107,7 +124,7 @@ public IRubyObject ruby_initialize(ThreadContext context, IRubyObject[] args) | |
args = Arity.scanArgs(context.runtime, args, 0, 1); | ||
IRubyObject data = args[0]; | ||
|
||
if (data.isNil()) { | ||
if (data == null || data.isNil()) { | ||
this.event = new Event(); | ||
} else if (data instanceof RubyHash) { | ||
HashMap<String, Object> newObj = Javafier.deep((RubyHash) data); | ||
|
@@ -215,7 +232,7 @@ public IRubyObject ruby_sprintf(ThreadContext context, IRubyObject format) throw | |
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(), LOGSTASH_ERROR, "timestamp field is missing", true); | ||
} | ||
} | ||
|
||
|
@@ -251,9 +268,38 @@ public IRubyObject ruby_to_java(ThreadContext context) | |
|
||
@JRubyMethod(name = "to_json", rest = true) | ||
public IRubyObject ruby_to_json(ThreadContext context, IRubyObject[] args) | ||
throws IOException | ||
{ | ||
return RubyString.newString(context.runtime, event.toJson()); | ||
try { | ||
return RubyString.newString(context.runtime, event.toJson()); | ||
} catch (Exception e) { | ||
throw new RaiseException(context.runtime, GENERATOR_ERROR, e.getMessage(), true); | ||
} | ||
} | ||
|
||
// @param value [String] the json string. A json object/map will convert to an array containing a single Event. | ||
// and a json array will convert each element into individual Event | ||
// @return Array<Event> array of events | ||
@JRubyMethod(name = "from_json", required = 1, meta = true) | ||
public static IRubyObject ruby_from_json(ThreadContext context, IRubyObject recv, RubyString value) | ||
{ | ||
Event[] events; | ||
try { | ||
events = Event.fromJson(value.asJavaString()); | ||
} catch (Exception e) { | ||
throw new RaiseException(context.runtime, PARSER_ERROR, e.getMessage(), true); | ||
} | ||
|
||
RubyArray result = RubyArray.newArray(context.runtime, events.length); | ||
|
||
if (events.length == 1) { | ||
// micro optimization for the 1 event more common use-case. | ||
result.set(0, RubyEvent.newRubyEvent(context.runtime, events[0])); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice shortcut |
||
} else { | ||
for (int i = 0; i < events.length; i++) { | ||
result.set(i, RubyEvent.newRubyEvent(context.runtime, events[i])); | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
@JRubyMethod(name = "validate_value", required = 1, meta = true) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice 👍