logstash-output-newrelic 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -29
- data/lib/logstash/outputs/newrelic.rb +38 -23
- data/lib/logstash/outputs/newrelic_version/version.rb +1 -1
- data/spec/outputs/newrelic_spec.rb +58 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6fb3ab8cf5881043a05b318e3a5158a15f9e39f71d35bf1b98a2b0526ec59df8
|
4
|
+
data.tar.gz: b78ec9ccaddeb88589815019ef3a6b8336b9b12aef7d51b03ccb07df21e7c679
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5d13fbb5791e8f7ecf98c6aaebae14596f94581246691cbc9b92a8129b97207405e7af396de356cf1a3bd8fbc882e77700be6353356f54c806a631b1052cd06
|
7
|
+
data.tar.gz: f57941893058a0fdd95c2ab7d3b307051275f428591314d5c2ae93afa71ad18cc29e7ec64bc17db17073670c031f1b0293525c675d00e8db52a1fddda6f85cce
|
data/README.md
CHANGED
@@ -6,13 +6,8 @@ This is a plugin for [Logstash](https://github.com/elastic/logstash) that output
|
|
6
6
|
Install the New Relic Logstash plugin using the following command:</br>
|
7
7
|
`logstash-plugin install logstash-output-newrelic`
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
```
|
13
|
-
Old version: 0.9.1 (unmaintained)
|
14
|
-
Current: 1.0.0
|
15
|
-
```
|
9
|
+
### Versions
|
10
|
+
Versions of this plugin less than 1.0.0 are unsupported.
|
16
11
|
|
17
12
|
## Configuration
|
18
13
|
|
@@ -50,7 +45,8 @@ output {
|
|
50
45
|
|
51
46
|
## Testing
|
52
47
|
|
53
|
-
An easy way to test the plugin is to make sure Logstash is getting input from a log file you
|
48
|
+
An easy way to test the plugin is to make sure Logstash is getting input from a log file you
|
49
|
+
can write to. Something like this in your logstash.conf:
|
54
50
|
```
|
55
51
|
input {
|
56
52
|
file {
|
@@ -62,32 +58,29 @@ input {
|
|
62
58
|
* Append a test log message to your log file: `echo "test message" >> /path/to/your/log/file`
|
63
59
|
* Search New Relic Logs for `"test message"`
|
64
60
|
|
65
|
-
##
|
61
|
+
## JSON message parsing
|
66
62
|
|
67
|
-
This plugin will attempt to parse any 'message' attribute as JSON -- if it is JSON,
|
63
|
+
This plugin will attempt to parse any 'message' attribute as JSON -- if it is JSON, it will be parsed and
|
64
|
+
the JSON attributes will be added to the event.
|
68
65
|
|
69
|
-
For example, the
|
66
|
+
For example, the event:
|
70
67
|
```
|
71
|
-
[{
|
72
|
-
"message": "some message",
|
73
|
-
"timestamp": 1531414060739
|
74
|
-
},
|
75
68
|
{
|
76
|
-
|
77
|
-
}
|
69
|
+
"timestamp": 1562767499238,
|
70
|
+
"message": "{\"service-name\": \"login-service\", \"user\": {\"id\": 123, \"name\": \"alice\"}}"
|
71
|
+
}
|
72
|
+
|
78
73
|
```
|
79
74
|
|
80
|
-
Will be
|
75
|
+
Will be treated as:
|
81
76
|
```
|
82
|
-
|
83
|
-
"
|
84
|
-
"
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
77
|
+
{
|
78
|
+
"timestamp": 1562767499238,
|
79
|
+
"message": "{\"service-name\": \"my-service\", \"user\": {\"id\": 123, \"name\": \"alice\"}}",
|
80
|
+
"service-name": "login-service",
|
81
|
+
"user": {
|
82
|
+
"id": 123,
|
83
|
+
"name": "alice"
|
84
|
+
}
|
85
|
+
}
|
89
86
|
```
|
90
|
-
|
91
|
-
## Development
|
92
|
-
|
93
|
-
See [DEVELOPER.md](DEVELOPER.md)
|
@@ -38,13 +38,32 @@ class LogStash::Outputs::NewRelic < LogStash::Outputs::Base
|
|
38
38
|
@executor&.shutdown
|
39
39
|
end
|
40
40
|
|
41
|
+
def time_to_milliseconds(time)
|
42
|
+
timestamp = time_to_logstash_timestamp(time)
|
43
|
+
if timestamp.nil?
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
|
47
|
+
(timestamp.to_f * 1000).to_i # to_f gives seconds with a fractional portion
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def time_to_logstash_timestamp(time)
|
52
|
+
begin
|
53
|
+
LogStash::Timestamp.coerce(time)
|
54
|
+
rescue
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
41
60
|
def encode(event_hash)
|
42
61
|
log_message_hash = {
|
43
|
-
|
62
|
+
:attributes => {}
|
44
63
|
}
|
45
64
|
|
46
65
|
if event_hash.has_key?('message')
|
47
|
-
log_message_hash[
|
66
|
+
log_message_hash[:attributes] = maybe_parse_json(event_hash['message'])
|
48
67
|
end
|
49
68
|
|
50
69
|
event_hash.each do |key, value|
|
@@ -52,22 +71,17 @@ class LogStash::Outputs::NewRelic < LogStash::Outputs::Base
|
|
52
71
|
# intrinsic attributes go at the top level
|
53
72
|
log_message_hash[key] = value
|
54
73
|
elsif key == '@timestamp'
|
55
|
-
|
74
|
+
milliseconds = time_to_milliseconds(value)
|
75
|
+
if !milliseconds.nil?
|
76
|
+
log_message_hash[:timestamp] = milliseconds
|
77
|
+
end
|
56
78
|
else
|
57
79
|
# non-intrinsic attributes get put into 'attributes'
|
58
|
-
log_message_hash[
|
80
|
+
log_message_hash[:attributes][key] = value
|
59
81
|
end
|
60
82
|
end
|
61
|
-
|
62
|
-
log_message_hash
|
63
|
-
end
|
64
83
|
|
65
|
-
|
66
|
-
if event_hash.has_key?('message')
|
67
|
-
message = event_hash['message']
|
68
|
-
event_hash = event_hash.merge(maybe_parse_json(message))
|
69
|
-
end
|
70
|
-
event_hash
|
84
|
+
log_message_hash
|
71
85
|
end
|
72
86
|
|
73
87
|
def maybe_parse_json(message)
|
@@ -77,8 +91,9 @@ class LogStash::Outputs::NewRelic < LogStash::Outputs::Base
|
|
77
91
|
return parsed
|
78
92
|
end
|
79
93
|
rescue JSON::ParserError
|
94
|
+
# Not JSON
|
80
95
|
end
|
81
|
-
|
96
|
+
{}
|
82
97
|
end
|
83
98
|
|
84
99
|
def multi_receive(events)
|
@@ -87,15 +102,15 @@ class LogStash::Outputs::NewRelic < LogStash::Outputs::Base
|
|
87
102
|
payload.push(encode(event.to_hash))
|
88
103
|
end
|
89
104
|
payload = {
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
105
|
+
:common => {
|
106
|
+
:attributes => {
|
107
|
+
:plugin => {
|
108
|
+
:type => 'logstash',
|
109
|
+
:version => LogStash::Outputs::NewRelicVersion::VERSION,
|
110
|
+
}
|
111
|
+
}
|
112
|
+
},
|
113
|
+
:logs => payload
|
99
114
|
}
|
100
115
|
@semaphor.acquire()
|
101
116
|
execute = @executor.java_method :submit, [java.lang.Runnable]
|
@@ -24,6 +24,13 @@ describe LogStash::Outputs::NewRelic do
|
|
24
24
|
}
|
25
25
|
}
|
26
26
|
|
27
|
+
# An arbitrary time to use in these tests, with different representations
|
28
|
+
class FixedTime
|
29
|
+
MILLISECONDS = 1562888528123
|
30
|
+
ISO_8601_STRING_TIME = '2019-07-11T23:42:08.123Z'
|
31
|
+
LOGSTASH_TIMESTAMP = LogStash::Timestamp.coerce(ISO_8601_STRING_TIME)
|
32
|
+
end
|
33
|
+
|
27
34
|
def gunzip(bytes)
|
28
35
|
gz = Zlib::GzipReader.new(StringIO.new(bytes))
|
29
36
|
gz.read
|
@@ -39,6 +46,16 @@ describe LogStash::Outputs::NewRelic do
|
|
39
46
|
JSON.parse(gunzip(body))
|
40
47
|
end
|
41
48
|
|
49
|
+
def now_in_milliseconds()
|
50
|
+
(Time.now.to_f * 1000).to_i # to_f gives seconds with a fractional portion
|
51
|
+
end
|
52
|
+
|
53
|
+
def within_five_seconds_of(time_in_millis, expected_in_millis)
|
54
|
+
five_seconds_in_millis = 5 * 1000
|
55
|
+
(time_in_millis - expected_in_millis).abs < five_seconds_in_millis
|
56
|
+
end
|
57
|
+
|
58
|
+
|
42
59
|
before(:each) do
|
43
60
|
@newrelic_output = LogStash::Plugin.lookup("output", "newrelic").new(simple_config)
|
44
61
|
@newrelic_output.register
|
@@ -61,7 +78,7 @@ describe LogStash::Outputs::NewRelic do
|
|
61
78
|
it "all present" do
|
62
79
|
stub_request(:any, base_uri).to_return(status: 200)
|
63
80
|
|
64
|
-
event = LogStash::Event.new({
|
81
|
+
event = LogStash::Event.new({:message => "Test message" })
|
65
82
|
@newrelic_output.multi_receive([event])
|
66
83
|
|
67
84
|
wait_for(a_request(:post, base_uri)
|
@@ -72,6 +89,7 @@ describe LogStash::Outputs::NewRelic do
|
|
72
89
|
})).to have_been_made
|
73
90
|
end
|
74
91
|
end
|
92
|
+
|
75
93
|
context "request body" do
|
76
94
|
|
77
95
|
it "message contains plugin information" do
|
@@ -88,16 +106,47 @@ describe LogStash::Outputs::NewRelic do
|
|
88
106
|
.to have_been_made
|
89
107
|
end
|
90
108
|
|
91
|
-
# TODO: why is this field always removed?
|
92
|
-
it "'@timestamp' field is removed" do
|
93
|
-
stub_request(:any, base_uri).to_return(status: 200)
|
94
109
|
|
95
|
-
|
96
|
-
@newrelic_output.multi_receive([event])
|
110
|
+
context "@timestamp field" do
|
97
111
|
|
98
|
-
|
99
|
-
.
|
100
|
-
|
112
|
+
def test_timestamp(timestamp, message_matcher)
|
113
|
+
stub_request(:any, base_uri).to_return(status: 200)
|
114
|
+
|
115
|
+
event = LogStash::Event.new({ :message => "Test message", :@timestamp => timestamp })
|
116
|
+
@newrelic_output.multi_receive([event])
|
117
|
+
|
118
|
+
wait_for(a_request(:post, base_uri)
|
119
|
+
.with { |request|
|
120
|
+
message = single_gzipped_message(request.body)
|
121
|
+
message_matcher.call(message)
|
122
|
+
}).to have_been_made
|
123
|
+
end
|
124
|
+
|
125
|
+
it "LogStash::Timestamp '@timestamp' field is added as 'timestamp' as milliseconds since epoch" do
|
126
|
+
def message_matcher(message)
|
127
|
+
message['timestamp'] == FixedTime::MILLISECONDS
|
128
|
+
end
|
129
|
+
|
130
|
+
test_timestamp(FixedTime::LOGSTASH_TIMESTAMP, method(:message_matcher))
|
131
|
+
end
|
132
|
+
|
133
|
+
it "String ISO 8601 '@timestamp' field is added as 'timestamp' as milliseconds since epoch" do
|
134
|
+
def message_matcher(message)
|
135
|
+
message['timestamp'] == FixedTime::MILLISECONDS
|
136
|
+
end
|
137
|
+
|
138
|
+
test_timestamp(FixedTime::ISO_8601_STRING_TIME, method(:message_matcher))
|
139
|
+
end
|
140
|
+
|
141
|
+
# Ideally we might not even set a timestamp if parsing fails. However, the time parsing library doesn't tell us if
|
142
|
+
# parsing fails -- it just returns the current time.
|
143
|
+
it "Unparseable '@timestamp' field is parsed as current time and put into 'timestamp'" do
|
144
|
+
def message_matcher(message)
|
145
|
+
within_five_seconds_of(message['timestamp'], now_in_milliseconds)
|
146
|
+
end
|
147
|
+
|
148
|
+
test_timestamp("Not an ISO 8601 string", method(:message_matcher))
|
149
|
+
end
|
101
150
|
end
|
102
151
|
|
103
152
|
it "all other fields passed through as is" do
|
@@ -109,7 +158,6 @@ describe LogStash::Outputs::NewRelic do
|
|
109
158
|
wait_for(a_request(:post, base_uri)
|
110
159
|
.with { |request|
|
111
160
|
message = single_gzipped_message(request.body)
|
112
|
-
puts message
|
113
161
|
message['message'] == 'Test message' &&
|
114
162
|
message['attributes']['other'] == 'Other value' })
|
115
163
|
.to have_been_made
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-newrelic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- New Relic Logging Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|