From 3fa7a4a97367388ab4f34a638878c888b4770f08 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Wed, 12 Mar 2014 10:31:33 +0100 Subject: [PATCH] logstash-event - initial gem2deb package. --- ruby-logstash-event/LICENSE | 14 ++ ruby-logstash-event/debian/changelog | 5 + ruby-logstash-event/debian/compat | 1 + ruby-logstash-event/debian/control | 19 ++ ruby-logstash-event/debian/copyright | 35 +++ .../debian/ruby-logstash-event.docs | 1 + ruby-logstash-event/debian/ruby-tests.rb | 13 + ruby-logstash-event/debian/rules | 15 ++ ruby-logstash-event/debian/source/format | 1 + ruby-logstash-event/debian/watch | 2 + ruby-logstash-event/lib/logstash-event.rb | 1 + ruby-logstash-event/lib/logstash/event.rb | 272 +++++++++++++++++++++ ruby-logstash-event/lib/logstash/namespace.rb | 15 ++ ruby-logstash-event/lib/logstash/util.rb | 105 ++++++++ .../lib/logstash/util/fieldreference.rb | 49 ++++ ruby-logstash-event/metadata.yml | 117 +++++++++ ruby-logstash-event/spec/event.rb | 139 +++++++++++ 17 files changed, 804 insertions(+) create mode 100644 ruby-logstash-event/LICENSE create mode 100644 ruby-logstash-event/debian/changelog create mode 100644 ruby-logstash-event/debian/compat create mode 100644 ruby-logstash-event/debian/control create mode 100644 ruby-logstash-event/debian/copyright create mode 100644 ruby-logstash-event/debian/ruby-logstash-event.docs create mode 100644 ruby-logstash-event/debian/ruby-tests.rb create mode 100755 ruby-logstash-event/debian/rules create mode 100644 ruby-logstash-event/debian/source/format create mode 100644 ruby-logstash-event/debian/watch create mode 100644 ruby-logstash-event/lib/logstash-event.rb create mode 100644 ruby-logstash-event/lib/logstash/event.rb create mode 100644 ruby-logstash-event/lib/logstash/namespace.rb create mode 100644 ruby-logstash-event/lib/logstash/util.rb create mode 100644 ruby-logstash-event/lib/logstash/util/fieldreference.rb create mode 100644 ruby-logstash-event/metadata.yml create mode 100644 ruby-logstash-event/spec/event.rb diff --git a/ruby-logstash-event/LICENSE b/ruby-logstash-event/LICENSE new file mode 100644 index 0000000..b3e3070 --- /dev/null +++ b/ruby-logstash-event/LICENSE @@ -0,0 +1,14 @@ +Copyright 2009-2013 Jordan Sissel, Pete Fritchman, and contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/ruby-logstash-event/debian/changelog b/ruby-logstash-event/debian/changelog new file mode 100644 index 0000000..2483582 --- /dev/null +++ b/ruby-logstash-event/debian/changelog @@ -0,0 +1,5 @@ +ruby-logstash-event (1.2.02-1) UNRELEASED; urgency=medium + + * Initial release (Closes: #nnnn) + + -- MAINTAINER Wed, 12 Mar 2014 10:30:49 +0100 diff --git a/ruby-logstash-event/debian/compat b/ruby-logstash-event/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/ruby-logstash-event/debian/compat @@ -0,0 +1 @@ +7 diff --git a/ruby-logstash-event/debian/control b/ruby-logstash-event/debian/control new file mode 100644 index 0000000..2c99de4 --- /dev/null +++ b/ruby-logstash-event/debian/control @@ -0,0 +1,19 @@ +Source: ruby-logstash-event +Section: ruby +Priority: optional +Maintainer: Debian Ruby Extras Maintainers +Uploaders: <> +Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.6.1~) +Standards-Version: 3.9.4 +#Vcs-Git: git://anonscm.debian.org/pkg-ruby-extras/ruby-logstash-event.git +#Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-ruby-extras/ruby-logstash-event.git;a=summary +Homepage: https://github.com/logstash/logstash +XS-Ruby-Versions: all + +Package: ruby-logstash-event +Architecture: all +XB-Ruby-Versions: ${ruby:Versions} +Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter +# rspec (>= 0, development), guard (>= 0, development), guard-rspec (>= 0, development), insist (= 1.0.0, development) +Description: Library that contains the classes required to create LogStash events + Library that contains the classes required to create LogStash events diff --git a/ruby-logstash-event/debian/copyright b/ruby-logstash-event/debian/copyright new file mode 100644 index 0000000..d514a3d --- /dev/null +++ b/ruby-logstash-event/debian/copyright @@ -0,0 +1,35 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: logstash-event +Source: FIXME + +Files: * +Copyright: + +License: GPL-2+ (FIXME) + +Files: debian/* +Copyright: 2014 <> +License: GPL-2+ (FIXME) +Comment: the Debian packaging is licensed under the same terms as the original package. + +License: GPL-2+ (FIXME) + This program is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later + version. + . + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the GNU General Public License for more + details. + . + You should have received a copy of the GNU General Public + License along with this package; if not, write to the Free + Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301 USA + . + On Debian systems, the full text of the GNU General Public + License version 2 can be found in the file + `/usr/share/common-licenses/GPL-2'. diff --git a/ruby-logstash-event/debian/ruby-logstash-event.docs b/ruby-logstash-event/debian/ruby-logstash-event.docs new file mode 100644 index 0000000..d0ab95f --- /dev/null +++ b/ruby-logstash-event/debian/ruby-logstash-event.docs @@ -0,0 +1 @@ +# FIXME: READMEs found diff --git a/ruby-logstash-event/debian/ruby-tests.rb b/ruby-logstash-event/debian/ruby-tests.rb new file mode 100644 index 0000000..eac5ce6 --- /dev/null +++ b/ruby-logstash-event/debian/ruby-tests.rb @@ -0,0 +1,13 @@ +# FIXME +# there's a spec/ or a test/ directory in the upstream source, but +# no test suite was defined in the Gem specification. It would be +# a good idea to define it here so the package gets tested at build time. +# Examples: +# $: << 'lib' << '.' +# Dir['{spec,test}/**/*.rb'].each { |f| require f } +# +# require 'test/ts_foo.rb' +# +# require 'rbconfig' +# ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']) +# exec("#{ruby} -I. test/runtests.rb") diff --git a/ruby-logstash-event/debian/rules b/ruby-logstash-event/debian/rules new file mode 100755 index 0000000..82ddc0c --- /dev/null +++ b/ruby-logstash-event/debian/rules @@ -0,0 +1,15 @@ +#!/usr/bin/make -f +#export DH_VERBOSE=1 +# +# Uncomment to ignore all test failures (but the tests will run anyway) +#export DH_RUBY_IGNORE_TESTS=all +# +# Uncomment to ignore some test failures (but the tests will run anyway). +# Valid values: +#export DH_RUBY_IGNORE_TESTS=ruby1.9.1 ruby2.0 require-rubygems +# +# If you need to specify the .gemspec (eg there is more than one) +#export DH_RUBY_GEMSPEC=gem.gemspec + +%: + dh $@ --buildsystem=ruby --with ruby diff --git a/ruby-logstash-event/debian/source/format b/ruby-logstash-event/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/ruby-logstash-event/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/ruby-logstash-event/debian/watch b/ruby-logstash-event/debian/watch new file mode 100644 index 0000000..539dfcd --- /dev/null +++ b/ruby-logstash-event/debian/watch @@ -0,0 +1,2 @@ +version=3 +http://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/logstash-event .*/logstash-event-(.*).tar.gz diff --git a/ruby-logstash-event/lib/logstash-event.rb b/ruby-logstash-event/lib/logstash-event.rb new file mode 100644 index 0000000..6444026 --- /dev/null +++ b/ruby-logstash-event/lib/logstash-event.rb @@ -0,0 +1 @@ +require "logstash/event" diff --git a/ruby-logstash-event/lib/logstash/event.rb b/ruby-logstash-event/lib/logstash/event.rb new file mode 100644 index 0000000..d3d2742 --- /dev/null +++ b/ruby-logstash-event/lib/logstash/event.rb @@ -0,0 +1,272 @@ +require "json" +require "time" +require "date" +require "logstash/namespace" +require "logstash/util/fieldreference" + +# Use a custom serialization for jsonifying Time objects. +# TODO(sissel): Put this in a separate file. +class Time + def to_json(*args) + return iso8601(3).to_json(*args) + end + + def inspect + return to_json + end +end + +# the logstash event object. +# +# An event is simply a tuple of (timestamp, data). +# The 'timestamp' is an ISO8601 timestamp. Data is anything - any message, +# context, references, etc that are relevant to this event. +# +# Internally, this is represented as a hash with only two guaranteed fields. +# +# * "@timestamp" - an ISO8601 timestamp representing the time the event +# occurred at. +# * "@version" - the version of the schema. Currently "1" +# +# They are prefixed with an "@" symbol to avoid clashing with your +# own custom fields. +# +# When serialized, this is represented in JSON. For example: +# +# { +# "@timestamp": "2013-02-09T20:39:26.234Z", +# "@version": "1", +# message: "hello world" +# } +class LogStash::Event + class DeprecatedMethod < StandardError; end + + public + def initialize(data={}) + @cancelled = false + + @data = data + if data.include?("@timestamp") + t = data["@timestamp"] + if t.is_a?(String) + data["@timestamp"] = Time.parse(t).gmtime + end + else + data["@timestamp"] = ::Time.now.utc + end + data["@version"] = "1" if !@data.include?("@version") + end # def initialize + + # Add class methods on inclusion. + public + def self.included(klass) + klass.extend(ClassMethods) + end # def included + + module ClassMethods + public + def from_json(json) + return self.new(JSON.parse(json)) + end # def from_json + end + + public + def cancel + @cancelled = true + end # def cancel + + public + def uncancel + @cancelled = false + end # def uncancel + + public + def cancelled? + return @cancelled + end # def cancelled? + + # Create a deep-ish copy of this event. + public + def clone + copy = {} + @data.each do |k,v| + # TODO(sissel): Recurse if this is a hash/array? + copy[k] = v.clone + end + return self.class.new(copy) + end # def clone + + if RUBY_ENGINE == "jruby" + public + def to_s + return self.sprintf("%{+yyyy-MM-dd'T'HH:mm:ss.SSSZ} %{host} %{message}") + end # def to_s + else + public + def to_s + return self.sprintf("#{self["@timestamp"].iso8601} %{host} %{message}") + end # def to_s + end + + public + def timestamp; return @data["@timestamp"]; end # def timestamp + def timestamp=(val); return @data["@timestamp"] = val; end # def timestamp= + + def unix_timestamp + raise DeprecatedMethod + end # def unix_timestamp + + def ruby_timestamp + raise DeprecatedMethod + end # def unix_timestamp + + # field-related access + public + def [](str) + if str[0,1] == "+" + else + return LogStash::Util::FieldReference.exec(str, @data) + end + end # def [] + + public + def []=(str, value) + r = LogStash::Util::FieldReference.exec(str, @data) do |obj, key| + obj[key] = value + end + + # The assignment can fail if the given field reference (str) does not exist + # In this case, we'll want to set the value manually. + if r.nil? + # TODO(sissel): Implement this in LogStash::Util::FieldReference + if str[0,1] != "[" + return @data[str] = value + end + + # No existing element was found, so let's set one. + *parents, key = str.scan(/(?<=\[)[^\]]+(?=\])/) + obj = @data + parents.each do |p| + if obj.include?(p) + obj = obj[p] + else + obj[p] = {} + obj = obj[p] + end + end + obj[key] = value + end + return value + end # def []= + + public + def fields + raise DeprecatedMethod + end + + public + def to_json(*args) + return @data.to_json(*args) + end # def to_json + + def to_hash + return @data + end # def to_hash + + public + def overwrite(event) + @data = event.to_hash + end + + public + def include?(key) + return !self[key].nil? + end # def include? + + # Append an event to this one. + public + def append(event) + # non-destructively merge that event with ourselves. + LogStash::Util.hash_merge(@data, event.to_hash) + end # append + + # Remove a field or field reference. Returns the value of that field when + # deleted + public + def remove(str) + return LogStash::Util::FieldReference.exec(str, @data) do |obj, key| + next obj.delete(key) + end + end # def remove + + # sprintf. This could use a better method name. + # The idea is to take an event and convert it to a string based on + # any format values, delimited by %{foo} where 'foo' is a field or + # metadata member. + # + # For example, if the event has type == "foo" and source == "bar" + # then this string: + # "type is %{type} and source is %{host}" + # will return + # "type is foo and source is bar" + # + # If a %{name} value is an array, then we will join by ',' + # If a %{name} value does not exist, then no substitution occurs. + # + # TODO(sissel): It is not clear what the value of a field that + # is an array (or hash?) should be. Join by comma? Something else? + public + def sprintf(format) + format = format.to_s + if format.index("%").nil? + return format + end + + return format.gsub(/%\{[^}]+\}/) do |tok| + # Take the inside of the %{ ... } + key = tok[2 ... -1] + + if key == "+%s" + # Got %{+%s}, support for unix epoch time + next @data["@timestamp"].to_i + elsif key[0,1] == "+" + t = @data["@timestamp"] + formatter = org.joda.time.format.DateTimeFormat.forPattern(key[1 .. -1])\ + .withZone(org.joda.time.DateTimeZone::UTC) + #next org.joda.time.Instant.new(t.tv_sec * 1000 + t.tv_usec / 1000).toDateTime.toString(formatter) + # Invoke a specific Instant constructor to avoid this warning in JRuby + # > ambiguous Java methods found, using org.joda.time.Instant(long) + org.joda.time.Instant.java_class.constructor(Java::long).new_instance( + t.tv_sec * 1000 + t.tv_usec / 1000 + ).to_java.toDateTime.toString(formatter) + else + value = self[key] + case value + when nil + tok # leave the %{foo} if this field does not exist in this event. + when Array + value.join(",") # Join by ',' if value is an array + when Hash + value.to_json # Convert hashes to json + else + value # otherwise return the value + end # case value + end # 'key' checking + end # format.gsub... + end # def sprintf + + # Shims to remove after event v1 is the default. + def tags=(value); self["tags"] = value; end + def tags; return self["tags"]; end + def message=(value); self["message"] = value; end + def source=(value); self["source"] = value; end + def type=(value); self["type"] = value; end + def type; return self["type"]; end + def fields; return self.to_hash; end + + def tag(value) + # Generalize this method for more usability + self["tags"] ||= [] + self["tags"] << value unless self["tags"].include?(value) + end +end # class LogStash::Event diff --git a/ruby-logstash-event/lib/logstash/namespace.rb b/ruby-logstash-event/lib/logstash/namespace.rb new file mode 100644 index 0000000..e2f8d04 --- /dev/null +++ b/ruby-logstash-event/lib/logstash/namespace.rb @@ -0,0 +1,15 @@ +#$: << File.join(File.dirname(__FILE__), "..", "..", "vendor", "bundle") + +module LogStash + module Inputs; end + module Outputs; end + module Filters; end + module Search; end + module Config; end + module File; end + module Web; end + module Util; end + module PluginMixins; end + + SHUTDOWN = :shutdown +end # module LogStash diff --git a/ruby-logstash-event/lib/logstash/util.rb b/ruby-logstash-event/lib/logstash/util.rb new file mode 100644 index 0000000..1012a4c --- /dev/null +++ b/ruby-logstash-event/lib/logstash/util.rb @@ -0,0 +1,105 @@ +require "logstash/namespace" + +module LogStash::Util + UNAME = case RbConfig::CONFIG["host_os"] + when /^linux/; "linux" + else; RbConfig::CONFIG["host_os"] + end + + PR_SET_NAME = 15 + def self.set_thread_name(name) + if RUBY_ENGINE == "jruby" + # Keep java and ruby thread names in sync. + Java::java.lang.Thread.currentThread.setName(name) + end + Thread.current[:name] = name + + if UNAME == "linux" + require "logstash/util/prctl" + # prctl PR_SET_NAME allows up to 16 bytes for a process name + # since MRI 1.9, JRuby, and Rubinius use system threads for this. + LibC.prctl(PR_SET_NAME, name[0..16], 0, 0, 0) + end + end # def set_thread_name + + # Merge hash 'src' into 'dst' nondestructively + # + # Duplicate keys will become array values + # + # [ src["foo"], dst["foo"] ] + def self.hash_merge(dst, src) + src.each do |name, svalue| + if dst.include?(name) + dvalue = dst[name] + if dvalue.is_a?(Hash) && svalue.is_a?(Hash) + dvalue = hash_merge(dvalue, svalue) + elsif svalue.is_a?(Array) + if dvalue.is_a?(Array) + # merge arrays without duplicates. + dvalue |= svalue + else + dvalue = [dvalue] | svalue + end + else + if dvalue.is_a?(Array) + dvalue << svalue unless dvalue.include?(svalue) + else + dvalue = [dvalue, svalue] unless dvalue == svalue + end + end + + dst[name] = dvalue + else + # dst doesn't have this key, just set it. + dst[name] = svalue + end + end + + return dst + end # def self.hash_merge + + # Merge hash 'src' into 'dst' nondestructively + # + # Duplicate keys will become array values + # Arrays merged will simply be appended. + # + # [ src["foo"], dst["foo"] ] + def self.hash_merge_with_dups(dst, src) + src.each do |name, svalue| + if dst.include?(name) + dvalue = dst[name] + if dvalue.is_a?(Hash) && svalue.is_a?(Hash) + dvalue = hash_merge(dvalue, svalue) + elsif svalue.is_a?(Array) + if dvalue.is_a?(Array) + # merge arrays without duplicates. + dvalue += svalue + else + dvalue = [dvalue] + svalue + end + else + if dvalue.is_a?(Array) + dvalue << svalue unless dvalue.include?(svalue) + else + dvalue = [dvalue, svalue] unless dvalue == svalue + end + end + + dst[name] = dvalue + else + # dst doesn't have this key, just set it. + dst[name] = svalue + end + end + + return dst + end # def self.hash_merge + + def self.hash_merge_many(*hashes) + dst = {} + hashes.each do |hash| + hash_merge_with_dups(dst, hash) + end + return dst + end # def hash_merge_many +end # module LogStash::Util diff --git a/ruby-logstash-event/lib/logstash/util/fieldreference.rb b/ruby-logstash-event/lib/logstash/util/fieldreference.rb new file mode 100644 index 0000000..b826a4b --- /dev/null +++ b/ruby-logstash-event/lib/logstash/util/fieldreference.rb @@ -0,0 +1,49 @@ +require "logstash/namespace" +require "logstash/util" + +module LogStash::Util::FieldReference + def compile(str) + if str[0,1] != '[' + return <<-"CODE" + lambda do |e, &block| + return block.call(e, #{str.inspect}) unless block.nil? + return e[#{str.inspect}] + end + CODE + end + + code = "lambda do |e, &block|\n" + selectors = str.scan(/(?<=\[).+?(?=\])/) + selectors.each_with_index do |tok, i| + last = (i == selectors.count() - 1) + code << " # [#{tok}]#{ last ? " (last selector)" : "" }\n" + + if last + code << <<-"CODE" + return block.call(e, #{tok.inspect}) unless block.nil? + CODE + end + + code << <<-"CODE" + if e.is_a?(Array) + e = e[#{tok.to_i}] + else + e = e[#{tok.inspect}] + end + return e if e.nil? + CODE + + end + code << "return e\nend" + #puts code + return code + end # def compile + + def exec(str, obj, &block) + @__fieldeval_cache ||= {} + @__fieldeval_cache[str] ||= eval(compile(str)) + return @__fieldeval_cache[str].call(obj, &block) + end + + extend self +end # module LogStash::Util::FieldReference diff --git a/ruby-logstash-event/metadata.yml b/ruby-logstash-event/metadata.yml new file mode 100644 index 0000000..6ebe83b --- /dev/null +++ b/ruby-logstash-event/metadata.yml @@ -0,0 +1,117 @@ +--- !ruby/object:Gem::Specification +name: logstash-event +version: !ruby/object:Gem::Version + version: 1.2.02 + prerelease: +platform: ruby +authors: +- Jordan Sissel +autorequire: +bindir: bin +cert_chain: [] +date: 2013-09-11 00:00:00.000000000 Z +dependencies: +- !ruby/object:Gem::Dependency + name: rspec + requirement: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' +- !ruby/object:Gem::Dependency + name: guard + requirement: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' +- !ruby/object:Gem::Dependency + name: guard-rspec + requirement: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' +- !ruby/object:Gem::Dependency + name: insist + requirement: !ruby/object:Gem::Requirement + none: false + requirements: + - - '=' + - !ruby/object:Gem::Version + version: 1.0.0 + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + none: false + requirements: + - - '=' + - !ruby/object:Gem::Version + version: 1.0.0 +description: Library that contains the classes required to create LogStash events +email: +- jls@semicomplete.com +executables: [] +extensions: [] +extra_rdoc_files: [] +files: +- lib/logstash-event.rb +- lib/logstash/event.rb +- lib/logstash/namespace.rb +- lib/logstash/util/fieldreference.rb +- lib/logstash/util.rb +- spec/event.rb +- LICENSE +homepage: https://github.com/logstash/logstash +licenses: +- Apache License (2.0) +post_install_message: +rdoc_options: [] +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' +required_rubygems_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ! '>=' + - !ruby/object:Gem::Version + version: '0' +requirements: [] +rubyforge_project: +rubygems_version: 1.8.25 +signing_key: +specification_version: 3 +summary: Library that contains the classes required to create LogStash events +test_files: [] diff --git a/ruby-logstash-event/spec/event.rb b/ruby-logstash-event/spec/event.rb new file mode 100644 index 0000000..4fd775a --- /dev/null +++ b/ruby-logstash-event/spec/event.rb @@ -0,0 +1,139 @@ +require "logstash/event" +require "insist" + +describe LogStash::Event do + subject do + LogStash::Event.new( + "@timestamp" => Time.iso8601("2013-01-01T00:00:00.000Z"), + "type" => "sprintf", + "message" => "hello world", + "tags" => [ "tag1" ], + "source" => "/home/foo", + "a" => "b", + "c" => { + "d" => "f", + "e" => {"f" => "g"} + }, + "f" => { "g" => { "h" => "i" } }, + "j" => { + "k1" => "v", + "k2" => [ "w", "x" ], + "k3" => {"4" => "m"}, + 5 => 6, + "5" => 7 + } + ) + end + + context "#sprintf" do + it "should report a unix timestamp for %{+%s}" do + insist { subject.sprintf("%{+%s}") } == "1356998400" + end + + it "should report a time with %{+format} syntax", :if => RUBY_ENGINE == "jruby" do + insist { subject.sprintf("%{+YYYY}") } == "2013" + insist { subject.sprintf("%{+MM}") } == "01" + insist { subject.sprintf("%{+HH}") } == "00" + end + + it "should report fields with %{field} syntax" do + insist { subject.sprintf("%{type}") } == "sprintf" + insist { subject.sprintf("%{message}") } == subject["message"] + end + + it "should print deep fields" do + insist { subject.sprintf("%{[j][k1]}") } == "v" + insist { subject.sprintf("%{[j][k2][0]}") } == "w" + end + + it "should be able to take a non-string for the format" do + insist { subject.sprintf(2) } == "2" + end + end + + context "#[]" do + it "should fetch data" do + insist { subject["type"] } == "sprintf" + end + it "should fetch fields" do + insist { subject["a"] } == "b" + insist { subject['c']['d'] } == "f" + end + it "should fetch deep fields" do + insist { subject["[j][k1]"] } == "v" + insist { subject["[c][d]"] } == "f" + insist { subject['[f][g][h]'] } == "i" + insist { subject['[j][k3][4]'] } == "m" + insist { subject['[j][5]'] } == 7 + + end + + it "should be fast?", :if => ENV["SPEEDTEST"] do + 2.times do + start = Time.now + 100000.times { subject["[j][k1]"] } + puts "Duration: #{Time.now - start}" + end + end + end + + context "#append" do + it "should append strings to an array" do + subject.append(LogStash::Event.new("message" => "another thing")) + insist { subject["message"] } == [ "hello world", "another thing" ] + end + + it "should concatenate tags" do + subject.append(LogStash::Event.new("tags" => [ "tag2" ])) + insist { subject["tags"] } == [ "tag1", "tag2" ] + end + + context "when event field is nil" do + it "should add single value as string" do + subject.append(LogStash::Event.new({"field1" => "append1"})) + insist { subject[ "field1" ] } == "append1" + end + it "should add multi values as array" do + subject.append(LogStash::Event.new({"field1" => [ "append1","append2" ]})) + insist { subject[ "field1" ] } == [ "append1","append2" ] + end + end + + context "when event field is a string" do + before { subject[ "field1" ] = "original1" } + + it "should append string to values, if different from current" do + subject.append(LogStash::Event.new({"field1" => "append1"})) + insist { subject[ "field1" ] } == [ "original1", "append1" ] + end + it "should not change value, if appended value is equal current" do + subject.append(LogStash::Event.new({"field1" => "original1"})) + insist { subject[ "field1" ] } == "original1" + end + it "should concatenate values in an array" do + subject.append(LogStash::Event.new({"field1" => [ "append1" ]})) + insist { subject[ "field1" ] } == [ "original1", "append1" ] + end + it "should join array, removing duplicates" do + subject.append(LogStash::Event.new({"field1" => [ "append1","original1" ]})) + insist { subject[ "field1" ] } == [ "original1", "append1" ] + end + end + context "when event field is an array" do + before { subject[ "field1" ] = [ "original1", "original2" ] } + + it "should append string values to array, if not present in array" do + subject.append(LogStash::Event.new({"field1" => "append1"})) + insist { subject[ "field1" ] } == [ "original1", "original2", "append1" ] + end + it "should not append string values, if the array already contains it" do + subject.append(LogStash::Event.new({"field1" => "original1"})) + insist { subject[ "field1" ] } == [ "original1", "original2" ] + end + it "should join array, removing duplicates" do + subject.append(LogStash::Event.new({"field1" => [ "append1","original1" ]})) + insist { subject[ "field1" ] } == [ "original1", "original2", "append1" ] + end + end + end +end -- 1.8.2.3