logstash-codec-csv 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5aaabef583e1e52a16f43545eb47083e02bc951c
4
- data.tar.gz: 3aa2c1b325eb41cd65796bd662b02ead367cdaf5
2
+ SHA256:
3
+ metadata.gz: ea5265ba1dbb2589596a6679118b058d9f73db36c548d8454b2e63a533808908
4
+ data.tar.gz: 45ddf7937e0f918f72318af5eb99cd3994811ca5f624c5d88071c2da4830790c
5
5
  SHA512:
6
- metadata.gz: b981ff851e9eb2c7576a58669dd4ffe3c0ce169236063fb103891be5bb3750d2e13f667f07abc20519d82c3fd8c061c9a4e952af8777216ee1213db3c3deadc5
7
- data.tar.gz: 8a51e1bff8a64063ae31294c1e498b7b90e54b32bdddf0d5504596d8fe922c6e631c0672aedb82021fe8c11f15f9c93ce09caa349f8e3a3d8ffa1b20a28e6391
6
+ metadata.gz: fba5feae76e970343fe6541d569cd5701f93d227186c60b13da1e93f41c3f4f24626701257c76169ca94e74a8c56a945a98576f5e169ef7f266e5ee12c8feb4e
7
+ data.tar.gz: f333ec425b38c6b5d83ea8cbeaaefc032bf2b0ec6de1580b9d08ba0561127f609742fa676408ce46ac366d8cf41d6cc76c9b952ebde55c9d9ee314a921821122
@@ -1,3 +1,8 @@
1
+ ## 1.0.0
2
+ - Fixed dependencies to work with logstash v6 and up. Overhauled to match features of the CSV Filter. Improved spec coverage [#4](https://github.com/logstash-plugins/logstash-codec-csv/pull/4)
3
+ ## 0.1.5
4
+ - Fixed asciidoc formatting for example [#3](https://github.com/logstash-plugins/logstash-codec-csv/pull/3)
5
+
1
6
  ## 0.1.4
2
7
  - Fix some documentation issues
3
8
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-2015 Elasticsearch <http://www.elasticsearch.org>
1
+ Copyright (c) 2012-2018 Elasticsearch <http://www.elasticsearch.org>
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ include::{include_path}/plugin_header.asciidoc[]
20
20
 
21
21
  ==== Description
22
22
 
23
-
23
+ The csv codec takes CSV data, parses it and passes it along.
24
24
 
25
25
  [id="plugins-{type}s-{plugin}-options"]
26
26
  ==== Csv Codec Configuration Options
@@ -28,6 +28,7 @@ include::{include_path}/plugin_header.asciidoc[]
28
28
  [cols="<,<,<",options="header",]
29
29
  |=======================================================================
30
30
  |Setting |Input type|Required
31
+ | <<plugins-{type}s-{plugin}-autodetect_column_names>> |<<boolean,boolean>>|No
31
32
  | <<plugins-{type}s-{plugin}-autogenerate_column_names>> |<<boolean,boolean>>|No
32
33
  | <<plugins-{type}s-{plugin}-charset>> |<<string,string>>, one of `["ASCII-8BIT", "UTF-8", "US-ASCII", "Big5", "Big5-HKSCS", "Big5-UAO", "CP949", "Emacs-Mule", "EUC-JP", "EUC-KR", "EUC-TW", "GB2312", "GB18030", "GBK", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "ISO-8859-16", "KOI8-R", "KOI8-U", "Shift_JIS", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE", "Windows-31J", "Windows-1250", "Windows-1251", "Windows-1252", "IBM437", "IBM737", "IBM775", "CP850", "IBM852", "CP852", "IBM855", "CP855", "IBM857", "IBM860", "IBM861", "IBM862", "IBM863", "IBM864", "IBM865", "IBM866", "IBM869", "Windows-1258", "GB1988", "macCentEuro", "macCroatian", "macCyrillic", "macGreek", "macIceland", "macRoman", "macRomania", "macThai", "macTurkish", "macUkraine", "CP950", "CP951", "IBM037", "stateless-ISO-2022-JP", "eucJP-ms", "CP51932", "EUC-JIS-2004", "GB12345", "ISO-2022-JP", "ISO-2022-JP-2", "CP50220", "CP50221", "Windows-1256", "Windows-1253", "Windows-1255", "Windows-1254", "TIS-620", "Windows-874", "Windows-1257", "MacJapanese", "UTF-7", "UTF8-MAC", "UTF-16", "UTF-32", "UTF8-DoCoMo", "SJIS-DoCoMo", "UTF8-KDDI", "SJIS-KDDI", "ISO-2022-JP-KDDI", "stateless-ISO-2022-JP-KDDI", "UTF8-SoftBank", "SJIS-SoftBank", "BINARY", "CP437", "CP737", "CP775", "IBM850", "CP857", "CP860", "CP861", "CP862", "CP863", "CP864", "CP865", "CP866", "CP869", "CP1258", "Big5-HKSCS:2008", "ebcdic-cp-us", "eucJP", "euc-jp-ms", "EUC-JISX0213", "eucKR", "eucTW", "EUC-CN", "eucCN", "CP936", "ISO2022-JP", "ISO2022-JP2", "ISO8859-1", "ISO8859-2", "ISO8859-3", "ISO8859-4", "ISO8859-5", "ISO8859-6", "CP1256", "ISO8859-7", "CP1253", "ISO8859-8", "CP1255", "ISO8859-9", "CP1254", "ISO8859-10", "ISO8859-11", "CP874", "ISO8859-13", "CP1257", "ISO8859-14", "ISO8859-15", "ISO8859-16", "CP878", "MacJapan", "ASCII", "ANSI_X3.4-1968", "646", "CP65000", "CP65001", "UTF-8-MAC", "UTF-8-HFS", "UCS-2BE", "UCS-4BE", "UCS-4LE", "CP932", "csWindows31J", "SJIS", "PCK", "CP1250", "CP1251", "CP1252", "external", "locale"]`|No
33
34
  | <<plugins-{type}s-{plugin}-columns>> |<<array,array>>|No
@@ -40,13 +41,22 @@ include::{include_path}/plugin_header.asciidoc[]
40
41
 
41
42
  &nbsp;
42
43
 
44
+ [id="plugins-{type}s-{plugin}-autodetect_column_names"]
45
+ ===== `autodetect_column_names`
46
+
47
+ * Value type is <<boolean,boolean>>
48
+ * Default value is `false`
49
+
50
+ Define whether column names should be auto-detected from the header column or not.
51
+ Defaults to false.
52
+
43
53
  [id="plugins-{type}s-{plugin}-autogenerate_column_names"]
44
54
  ===== `autogenerate_column_names`
45
55
 
46
56
  * Value type is <<boolean,boolean>>
47
57
  * Default value is `true`
48
58
 
49
- Define whether column names should autogenerated or not.
59
+ Define whether column names should be autogenerated or not.
50
60
  Defaults to true. If set to false, columns not having a header specified will not be parsed.
51
61
 
52
62
  [id="plugins-{type}s-{plugin}-charset"]
@@ -65,12 +75,14 @@ The character encoding used in this codec. Examples include "UTF-8" and
65
75
  * Value type is <<array,array>>
66
76
  * Default value is `[]`
67
77
 
78
+ **When decoding:**
68
79
  Define a list of column names (in the order they appear in the CSV,
69
80
  as if it were a header line). If `columns` is not configured, or there
70
81
  are not enough columns specified, the default column names are
71
- "column1", "column2", etc. In the case that there are more columns
72
- in the data than specified in this column list, extra columns will be auto-numbered:
73
- (e.g. "user_defined_1", "user_defined_2", "column3", "column4", etc.)
82
+ "column1", "column2", etc.
83
+
84
+ **When encoding:**
85
+ List of fields names to include in the encoded CSV, in the order listed.
74
86
 
75
87
  [id="plugins-{type}s-{plugin}-convert"]
76
88
  ===== `convert`
@@ -79,9 +91,10 @@ in the data than specified in this column list, extra columns will be auto-numbe
79
91
  * Default value is `{}`
80
92
 
81
93
  Define a set of datatype conversions to be applied to columns.
82
- Possible conversions are integer, float, date, date_time, boolean
94
+ Possible conversions are: `integer`, `float`, `date`, `date_time`, `boolean`
95
+
83
96
 
84
- # Example:
97
+ *Example*
85
98
  [source,ruby]
86
99
  filter {
87
100
  csv {
@@ -95,10 +108,8 @@ Possible conversions are integer, float, date, date_time, boolean
95
108
  * Value type is <<boolean,boolean>>
96
109
  * Default value is `false`
97
110
 
98
- Treats the first line received as the hearder information, this information will
99
- be used to compose the field names in the generated events. Note this information can
100
- be reset on demand, useful for example when dealing with new files in the file input
101
- or new request in the http_poller. Default => false
111
+ When **encoding** in an output plugin, include headers in the encoded CSV
112
+ once per codec lifecyle (not for every event). Default => false
102
113
 
103
114
  [id="plugins-{type}s-{plugin}-quote_char"]
104
115
  ===== `quote_char`
@@ -127,6 +138,6 @@ Optional.
127
138
  * Default value is `false`
128
139
 
129
140
  Define whether empty columns should be skipped.
130
- Defaults to false. If set to true, columns containing no value will not get set.
141
+ Defaults to false. If set to true, columns containing no value will not be included.
131
142
 
132
143
 
@@ -7,12 +7,13 @@ class LogStash::Codecs::CSV < LogStash::Codecs::Base
7
7
 
8
8
  config_name "csv"
9
9
 
10
- # Define a list of column names (in the order they appear in the CSV,
11
- # as if it were a header line). If `columns` is not configured, or there
12
- # are not enough columns specified, the default column names are
13
- # "column1", "column2", etc. In the case that there are more columns
14
- # in the data than specified in this column list, extra columns will be auto-numbered:
15
- # (e.g. "user_defined_1", "user_defined_2", "column3", "column4", etc.)
10
+ # When decoding:
11
+ # Define a list of column names (in the order they appear in the CSV,
12
+ # as if it were a header line). If `columns` is not configured, or there
13
+ # are not enough columns specified, the default column names are
14
+ # "column1", "column2", etc.
15
+ # When encoding:
16
+ # List of fields names to include in the encoded CSV, in the order listed.
16
17
  config :columns, :validate => :array, :default => []
17
18
 
18
19
  # Define the column separator value. If this is not specified, the default
@@ -25,20 +26,22 @@ class LogStash::Codecs::CSV < LogStash::Codecs::Base
25
26
  # Optional.
26
27
  config :quote_char, :validate => :string, :default => '"'
27
28
 
28
- # Treats the first line received as the hearder information, this information will
29
- # be used to compose the field names in the generated events. Note this information can
30
- # be reset on demand, useful for example when dealing with new files in the file input
31
- # or new request in the http_poller. Default => false
29
+ # When encoding in an output plugin, include headers in the encoded CSV
30
+ # once per codec lifecyle (not for every event). Default => false
32
31
  config :include_headers, :validate => :boolean, :default => false
33
32
 
34
- # Define whether column names should autogenerated or not.
33
+ # Define whether column names should be autogenerated or not.
35
34
  # Defaults to true. If set to false, columns not having a header specified will not be parsed.
36
35
  config :autogenerate_column_names, :validate => :boolean, :default => true
37
36
 
38
37
  # Define whether empty columns should be skipped.
39
- # Defaults to false. If set to true, columns containing no value will not get set.
38
+ # Defaults to false. If set to true, columns containing no value will not be included.
40
39
  config :skip_empty_columns, :validate => :boolean, :default => false
41
40
 
41
+ # Define whether column names should be auto-detected from the header column or not.
42
+ # Defaults to false.
43
+ config :autodetect_column_names, :validate => :boolean, :default => false
44
+
42
45
  # Define a set of datatype conversions to be applied to columns.
43
46
  # Possible conversions are integer, float, date, date_time, boolean
44
47
  #
@@ -51,113 +54,120 @@ class LogStash::Codecs::CSV < LogStash::Codecs::Base
51
54
  # }
52
55
  config :convert, :validate => :hash, :default => {}
53
56
 
54
- ##
55
- # List of valid conversion types used for the convert option
56
- ##
57
- VALID_CONVERT_TYPES = [ "integer", "float", "date", "date_time", "boolean" ].freeze
58
-
59
-
60
57
  # The character encoding used in this codec. Examples include "UTF-8" and
61
58
  # "CP1252".
62
59
  config :charset, :validate => ::Encoding.name_list, :default => "UTF-8"
63
60
 
61
+ CONVERTERS = {
62
+ :integer => lambda do |value|
63
+ CSV::Converters[:integer].call(value)
64
+ end,
65
+
66
+ :float => lambda do |value|
67
+ CSV::Converters[:float].call(value)
68
+ end,
69
+
70
+ :date => lambda do |value|
71
+ result = CSV::Converters[:date].call(value)
72
+ result.is_a?(Date) ? LogStash::Timestamp.new(result.to_time) : result
73
+ end,
74
+
75
+ :date_time => lambda do |value|
76
+ result = CSV::Converters[:date_time].call(value)
77
+ result.is_a?(DateTime) ? LogStash::Timestamp.new(result.to_time) : result
78
+ end,
79
+
80
+ :boolean => lambda do |value|
81
+ value = value.strip.downcase
82
+ return false if value == "false"
83
+ return true if value == "true"
84
+ return value
85
+ end
86
+ }
87
+ CONVERTERS.default = lambda {|v| v}
88
+ CONVERTERS.freeze
89
+
64
90
  def register
65
91
  @converter = LogStash::Util::Charset.new(@charset)
66
92
  @converter.logger = @logger
67
93
 
68
94
  # validate conversion types to be the valid ones.
69
- @convert.each_pair do |column, type|
70
- if !VALID_CONVERT_TYPES.include?(type)
71
- raise LogStash::ConfigurationError, "#{type} is not a valid conversion type."
72
- end
95
+ bad_types = @convert.values.select do |type|
96
+ !CONVERTERS.has_key?(type.to_sym)
97
+ end.uniq
98
+ raise(LogStash::ConfigurationError, "Invalid conversion types: #{bad_types.join(', ')}") unless bad_types.empty?
99
+
100
+ # @convert_symbols contains the symbolized types to avoid symbol conversion in the transform method
101
+ @convert_symbols = @convert.each_with_object({}){|(k, v), result| result[k] = v.to_sym}
102
+
103
+ # if the zero byte character is entered in the config, set the value
104
+ if (@quote_char == "\\x00")
105
+ @quote_char = "\x00"
73
106
  end
74
107
 
75
- @headers = false
76
- @options = { :col_sep => @separator, :quote_char => @quote_char }
108
+ @logger.debug? && @logger.debug("CSV parsing options", :col_sep => @separator, :quote_char => @quote_char)
77
109
  end
78
110
 
79
111
  def decode(data)
80
112
  data = @converter.convert(data)
81
113
  begin
82
- values = CSV.parse_line(data, @options)
83
- if @include_headers && !@headers
84
- @headers = true
85
- @options[:headers] = values
86
- else
87
- decoded = {}
88
- values.each_with_index do |fields, index|
89
- field_name, value = nil, nil
90
- if fields.is_a?(String) && !( @skip_empty_columns && fields.nil?) # No headers
91
- next if ignore_field?(index)
92
- field_name = ( !@columns[index].nil? ? @columns[index] : "column#{(index+1)}")
93
- value = fields
94
- elsif fields.is_a?(Array) # Got headers
95
- field_name = fields[0]
96
- value = fields[1]
114
+ values = CSV.parse_line(data, :col_sep => @separator, :quote_char => @quote_char)
115
+
116
+ if (@autodetect_column_names && @columns.empty?)
117
+ @columns = values
118
+ @logger.debug? && @logger.debug("Auto detected the following columns", :columns => @columns.inspect)
119
+ return
120
+ end
121
+
122
+ decoded = {}
123
+ values.each_index do |i|
124
+ unless (@skip_empty_columns && (values[i].nil? || values[i].empty?))
125
+ unless ignore_field?(i)
126
+ field_name = @columns[i] || "column#{i + 1}"
127
+ decoded[field_name] = transform(field_name, values[i])
97
128
  end
98
- next unless field_name
99
- decoded[field_name] = if should_transform?(field_name)
100
- transform(field_name, value)
101
- else
102
- value
103
- end
104
129
  end
105
- yield LogStash::Event.new(decoded) if block_given?
106
130
  end
131
+
132
+ yield LogStash::Event.new(decoded)
107
133
  rescue CSV::MalformedCSVError => e
108
- @logger.info("CSV parse failure. Falling back to plain-text", :error => e, :data => data)
109
- yield LogStash::Event.new("message" => data, "tags" => ["_csvparsefailure"]) if block_given?
134
+ @logger.error("CSV parse failure. Falling back to plain-text", :error => e, :data => data)
135
+ yield LogStash::Event.new("message" => data, "tags" => ["_csvparsefailure"])
110
136
  end
111
137
  end
112
138
 
113
139
  def encode(event)
114
- csv_data = CSV.generate_line(event.to_hash.values, @options)
115
- @on_event.call(event, csv_data)
116
- end
140
+ if @include_headers
141
+ csv_data = CSV.generate_line(select_keys(event), :col_sep => @separator, :quote_char => @quote_char, :headers => true)
142
+ @on_event.call(event, csv_data)
143
+
144
+ # output headers only once per codec lifecycle
145
+ @include_headers = false
146
+ end
117
147
 
118
- def reset
119
- @headers = false
120
- @options.delete(:headers)
148
+ csv_data = CSV.generate_line(select_values(event), :col_sep => @separator, :quote_char => @quote_char)
149
+ @on_event.call(event, csv_data)
121
150
  end
122
151
 
123
152
  private
124
153
 
125
- def ignore_field?(index)
126
- !@columns[index] && !@autogenerate_column_names
154
+ def select_values(event)
155
+ if @columns.empty?
156
+ event.to_hash.values
157
+ else
158
+ @columns.map {|column| event.get(column)}
159
+ end
127
160
  end
128
161
 
129
- def should_transform?(field_name)
130
- !@convert[field_name].nil?
162
+ def select_keys(event)
163
+ @columns.empty? ? event.to_hash.keys : @columns
131
164
  end
132
165
 
133
- def transform(field_name, value)
134
- transformation = @convert[field_name].to_sym
135
- converters[transformation].call(value)
166
+ def ignore_field?(index)
167
+ !@columns[index] && !@autogenerate_column_names
136
168
  end
137
169
 
138
- def converters
139
- @converters ||= {
140
- :integer => lambda do |value|
141
- CSV::Converters[:integer].call(value)
142
- end,
143
- :float => lambda do |value|
144
- CSV::Converters[:float].call(value)
145
-
146
- end,
147
- :date => lambda do |value|
148
- CSV::Converters[:date].call(value)
149
-
150
- end,
151
- :date_time => lambda do |value|
152
- CSV::Converters[:date_time].call(value)
153
- end,
154
- :boolean => lambda do |value|
155
- value = value.strip.downcase
156
- return false if value == "false"
157
- return true if value == "true"
158
- return value
159
- end
160
- }
170
+ def transform(field_name, value)
171
+ CONVERTERS[@convert_symbols[field_name]].call(value)
161
172
  end
162
-
163
- end # class LogStash::Codecs::Plain
173
+ end
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-codec-csv'
4
- s.version = '0.1.4'
4
+ s.version = '1.0.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "The csv codec take CSV data, parses it and passes it away"
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.metadata = { "logstash_plugin" => "true", "logstash_group" => "codec" }
21
21
 
22
22
  # Gem dependencies
23
- s.add_runtime_dependency "logstash-core-plugin-api", "~> 1.0"
23
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
24
 
25
25
  s.add_development_dependency 'logstash-devutils'
26
26
  end
@@ -12,14 +12,13 @@ describe LogStash::Codecs::CSV do
12
12
  end
13
13
 
14
14
  describe "decode" do
15
-
16
15
  let(:data) { "big,bird,sesame street" }
17
16
 
18
17
  it "return an event from CSV data" do
19
18
  codec.decode(data) do |event|
20
- expect(event["column1"]).to eq("big")
21
- expect(event["column2"]).to eq("bird")
22
- expect(event["column3"]).to eq("sesame street")
19
+ expect(event.get("column1")).to eq("big")
20
+ expect(event.get("column2")).to eq("bird")
21
+ expect(event.get("column3")).to eq("sesame street")
23
22
  end
24
23
  end
25
24
 
@@ -31,9 +30,9 @@ describe LogStash::Codecs::CSV do
31
30
 
32
31
  it "extract all the values" do
33
32
  codec.decode(data) do |event|
34
- expect(event["first"]).to eq("big")
35
- expect(event["last"]).to eq("bird")
36
- expect(event["address"]).to eq("sesame street")
33
+ expect(event.get("first")).to eq("big")
34
+ expect(event.get("last")).to eq("bird")
35
+ expect(event.get("address")).to eq("sesame street")
37
36
  end
38
37
  end
39
38
 
@@ -48,9 +47,9 @@ describe LogStash::Codecs::CSV do
48
47
 
49
48
  it "extract all the values" do
50
49
  codec.decode(data) do |event|
51
- expect(event["custom1"]).to eq("val1")
50
+ expect(event.get("custom1")).to eq("val1")
52
51
  expect(event.to_hash).not_to include("custom2")
53
- expect(event["custom3"]).to eq("val3")
52
+ expect(event.get("custom3")).to eq("val3")
54
53
  end
55
54
  end
56
55
  end
@@ -65,9 +64,9 @@ describe LogStash::Codecs::CSV do
65
64
 
66
65
  it "extract all the values" do
67
66
  codec.decode(data) do |event|
68
- expect(event["custom1"]).to eq("val1")
69
- expect(event["custom2"]).to eq("val2")
70
- expect(event["column3"]).to be_falsey
67
+ expect(event.get("custom1")).to eq("val1")
68
+ expect(event.get("custom2")).to eq("val2")
69
+ expect(event.get("column3")).to be_falsey
71
70
  end
72
71
  end
73
72
  end
@@ -83,8 +82,8 @@ describe LogStash::Codecs::CSV do
83
82
 
84
83
  it "return an event from CSV data" do
85
84
  codec.decode(data) do |event|
86
- expect(event["column1"]).to eq("big,bird")
87
- expect(event["column2"]).to eq("sesame street")
85
+ expect(event.get("column1")).to eq("big,bird")
86
+ expect(event.get("column2")).to eq("sesame street")
88
87
  end
89
88
  end
90
89
  end
@@ -98,9 +97,9 @@ describe LogStash::Codecs::CSV do
98
97
 
99
98
  it "return an event from CSV data" do
100
99
  codec.decode(data) do |event|
101
- expect(event["column1"]).to eq("big")
102
- expect(event["column2"]).to eq("bird")
103
- expect(event["column3"]).to eq("sesame street")
100
+ expect(event.get("column1")).to eq("big")
101
+ expect(event.get("column2")).to eq("bird")
102
+ expect(event.get("column3")).to eq("sesame street")
104
103
  end
105
104
  end
106
105
 
@@ -110,9 +109,9 @@ describe LogStash::Codecs::CSV do
110
109
 
111
110
  it "return an event from CSV data" do
112
111
  codec.decode(data) do |event|
113
- expect(event["column1"]).to eq("big")
114
- expect(event["column2"]).to eq("bird")
115
- expect(event["column3"]).to eq("sesame, street")
112
+ expect(event.get("column1")).to eq("big")
113
+ expect(event.get("column2")).to eq("bird")
114
+ expect(event.get("column3")).to eq("sesame, street")
116
115
  end
117
116
  end
118
117
  end
@@ -125,9 +124,9 @@ describe LogStash::Codecs::CSV do
125
124
 
126
125
  it "return an event from CSV data" do
127
126
  codec.decode(data) do |event|
128
- expect(event["column1"]).to eq("big")
129
- expect(event["column2"]).to eq("bird")
130
- expect(event["column3"]).to eq('"sesame" street')
127
+ expect(event.get("column1")).to eq("big")
128
+ expect(event.get("column2")).to eq("bird")
129
+ expect(event.get("column3")).to eq('"sesame" street')
131
130
  end
132
131
  end
133
132
  end
@@ -144,28 +143,15 @@ describe LogStash::Codecs::CSV do
144
143
  end
145
144
 
146
145
  let(:config) do
147
- { "include_headers" => true }
146
+ { "autodetect_column_names" => true }
148
147
  end
149
148
 
150
149
  it "include header information when requested" do
151
150
  codec.decode(data[0]) # Read the headers
152
151
  codec.decode(data[1]) do |event|
153
- expect(event["size"]).to eq("big")
154
- expect(event["animal"]).to eq("bird")
155
- expect(event["movie"]).to eq("sesame street")
156
- end
157
- end
158
-
159
- it "reset headers and fetch the new ones" do
160
- data.each do |row|
161
- codec.decode(row)
162
- end
163
- codec.reset
164
- codec.decode(new_data[0]) # set the new headers
165
- codec.decode(new_data[1]) do |event|
166
- expect(event["host"]).to eq("example.com")
167
- expect(event["country"]).to eq("germany")
168
- expect(event["city"]).to eq("berlin")
152
+ expect(event.get("size")).to eq("big")
153
+ expect(event.get("animal")).to eq("bird")
154
+ expect(event.get("movie")).to eq("sesame street")
169
155
  end
170
156
  end
171
157
  end
@@ -179,9 +165,9 @@ describe LogStash::Codecs::CSV do
179
165
 
180
166
  it "get converted values to the expected type" do
181
167
  codec.decode(data) do |event|
182
- expect(event["column1"]).to eq(1234)
183
- expect(event["column2"]).to eq("bird")
184
- expect(event["column3"]).to eq(false)
168
+ expect(event.get("column1")).to eq(1234)
169
+ expect(event.get("column2")).to eq("bird")
170
+ expect(event.get("column3")).to eq(false)
185
171
  end
186
172
  end
187
173
 
@@ -194,13 +180,80 @@ describe LogStash::Codecs::CSV do
194
180
 
195
181
  it "get converted values to the expected type" do
196
182
  codec.decode(data) do |event|
197
- expect(event["custom1"]).to eq(1234)
198
- expect(event["custom2"]).to eq("bird")
199
- expect(event["custom3"]).to eq(false)
183
+ expect(event.get("custom1")).to eq(1234)
184
+ expect(event.get("custom2")).to eq("bird")
185
+ expect(event.get("custom3")).to eq(false)
200
186
  end
201
187
  end
202
188
  end
203
189
  end
190
+ end
191
+
192
+ describe "encode" do
193
+ context "not including headers" do
194
+ let(:event) { LogStash::Event.new({"f1" => "v1", "f2" => "v2"}) }
195
+
196
+ context "without columns" do
197
+ let(:config) do
198
+ { "include_headers" => false, "columns" => [] }
199
+ end
204
200
 
201
+ it "should encode to single CSV line" do
202
+ codec.on_event do |e, d|
203
+ expect(d.chomp.split(",").sort).to eq("v1,v2,1,#{event.timestamp}".split(",").sort)
204
+ end
205
+ codec.encode(event)
206
+ end
207
+ end
208
+
209
+ context "with columns" do
210
+ let(:config) do
211
+ { "include_headers" => false, "columns" => ["f1", "f2"] }
212
+ end
213
+
214
+ it "should encode to single CSV line" do
215
+ codec.on_event do |e, d|
216
+ expect(d).to eq("v1,v2\n")
217
+ end
218
+ codec.encode(event)
219
+ end
220
+ end
221
+ end
222
+
223
+ context "including headers" do
224
+ let(:event) { LogStash::Event.new({"f1" => "v1", "f2" => "v2"}) }
225
+
226
+ context "without columns" do
227
+ let(:config) do
228
+ { "include_headers" => true, "columns" => [] }
229
+ end
230
+
231
+ it "should encode to two CSV line" do
232
+ lines = []
233
+ codec.on_event do |e, d|
234
+ lines << d
235
+ end
236
+ codec.encode(event)
237
+ expect(lines[0].chomp.split(",").sort).to eq("f1,f2,@version,@timestamp".split(",").sort)
238
+ expect(lines[1].chomp.split(",").sort).to eq("v1,v2,1,#{event.timestamp}".split(",").sort)
239
+ end
240
+ end
241
+
242
+ context "with columns" do
243
+ let(:config) do
244
+ { "include_headers" => true, "columns" => ["f1", "f2"] }
245
+ end
246
+
247
+ it "should encode to two CSV line" do
248
+ lines = []
249
+ codec.on_event do |e, d|
250
+ lines << d
251
+ end
252
+ codec.encode(event)
253
+ expect(lines[0]).to eq("f1,f2\n")
254
+ expect(lines[1]).to eq("v1,v2\n")
255
+ end
256
+ end
257
+ end
205
258
  end
206
259
  end
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-codec-csv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elasticsearch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-15 00:00:00.000000000 Z
11
+ date: 2020-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.60'
19
+ - - "<="
17
20
  - !ruby/object:Gem::Version
18
- version: '1.0'
21
+ version: '2.99'
19
22
  name: logstash-core-plugin-api
20
23
  prerelease: false
21
24
  type: :runtime
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.60'
30
+ - - "<="
25
31
  - !ruby/object:Gem::Version
26
- version: '1.0'
32
+ version: '2.99'
27
33
  - !ruby/object:Gem::Dependency
28
34
  requirement: !ruby/object:Gem::Requirement
29
35
  requirements:
@@ -38,7 +44,9 @@ dependencies:
38
44
  - - ">="
39
45
  - !ruby/object:Gem::Version
40
46
  version: '0'
41
- description: This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program
47
+ description: This gem is a Logstash plugin required to be installed on top of the
48
+ Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
49
+ gem is not a stand-alone program
42
50
  email: info@elasticsearch.com
43
51
  executables: []
44
52
  extensions: []
@@ -75,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
83
  version: '0'
76
84
  requirements: []
77
85
  rubyforge_project:
78
- rubygems_version: 2.4.8
86
+ rubygems_version: 2.6.13
79
87
  signing_key:
80
88
  specification_version: 4
81
89
  summary: The csv codec take CSV data, parses it and passes it away