fluent-plugin-systemd 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +91 -15
- data/lib/fluent/plugin/filter_systemd_entry.rb +29 -0
- data/lib/fluent/plugin/in_systemd.rb +34 -10
- data/lib/fluent/plugin/systemd/entry_mutator.rb +151 -0
- data/lib/fluent/plugin/systemd/pos_writer.rb +2 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14abb1b9c6b985bbaee61aae73791108578c738e
|
4
|
+
data.tar.gz: ab54b3167ad1832efd73d15eff17d0b4ed2d6e0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26dca0c3b93b49899fbb903ccfc66f79d9f2ded5416ce1bdd28b920b83583a4de29c812a426aabe9aad4b5718055b532f2fcaa6c2b15d77e4ea8bcb46fcebe23
|
7
|
+
data.tar.gz: a715f762f61481b93c1179af10c30f978cbafad7c01ffdd136a79e6d21757d5ce449f59640887d875fc74327c1c1c51d2d09a08eee1a0f1760054ecfc111c9e7
|
data/README.md
CHANGED
@@ -1,45 +1,57 @@
|
|
1
|
-
# systemd
|
1
|
+
# systemd plugin for [Fluentd](http://github.com/fluent/fluentd)
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/reevoo/fluent-plugin-systemd.svg?branch=master)](https://travis-ci.org/reevoo/fluent-plugin-systemd) [![Code Climate GPA](https://codeclimate.com/github/reevoo/fluent-plugin-systemd/badges/gpa.svg)](https://codeclimate.com/github/reevoo/fluent-plugin-systemd) [![Gem Version](https://badge.fury.io/rb/fluent-plugin-systemd.svg)](https://rubygems.org/gems/fluent-plugin-systemd)
|
4
4
|
|
5
|
-
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
**systemd** input plugin reads logs from the systemd journal
|
8
|
+
**systemd** filter plugin allows for basic manipulation of systemd journal entries
|
9
|
+
|
10
|
+
## Support
|
11
|
+
|
12
|
+
[![Fluentd Slack](http://slack.fluentd.org/badge.svg)](http://slack.fluentd.org/)
|
13
|
+
|
14
|
+
Join the #plugin-systemd channel on the [Fluentd Slack](http://slack.fluentd.org/)
|
6
15
|
|
7
16
|
|
17
|
+
## Requirements
|
18
|
+
|
8
19
|
|fluent-plugin-systemd|fluentd|td-agent|ruby|
|
9
20
|
|----|----|----|----|
|
10
|
-
| 0.
|
21
|
+
| > 0.1.0 | >= 0.14.11, < 2 | 3 | >= 2.1 |
|
11
22
|
| 0.0.x | ~> 0.12.0 | 2 | >= 1.9 |
|
12
23
|
|
13
|
-
* The 0.
|
24
|
+
* The 0.x.x series is developed from this branch (master)
|
14
25
|
* The 0.0.x series (compatible with fluentd v0.12, and td-agent 2) is developed on the [0.0.x branch](https://github.com/reevoo/fluent-plugin-systemd/tree/0.0.x)
|
15
26
|
|
16
|
-
## Overview
|
17
|
-
|
18
|
-
**systemd** input plugin reads logs from the systemd journal
|
19
|
-
|
20
27
|
## Installation
|
21
28
|
|
22
29
|
Simply use RubyGems:
|
23
30
|
|
24
|
-
gem install fluent-plugin-systemd -v 0.
|
31
|
+
gem install fluent-plugin-systemd -v 0.3.0
|
25
32
|
|
26
33
|
or
|
27
34
|
|
28
|
-
td-agent-gem install fluent-plugin-systemd -v 0.
|
35
|
+
td-agent-gem install fluent-plugin-systemd -v 0.3.0
|
29
36
|
|
30
|
-
## Configuration
|
37
|
+
## Input Plugin Configuration
|
31
38
|
|
32
39
|
<source>
|
33
40
|
@type systemd
|
41
|
+
tag kube-proxy
|
34
42
|
path /var/log/journal
|
35
43
|
filters [{ "_SYSTEMD_UNIT": "kube-proxy.service" }]
|
44
|
+
read_from_head true
|
36
45
|
<storage>
|
37
46
|
@type local
|
38
47
|
persistent true
|
39
48
|
path kube-proxy.pos
|
40
49
|
</storage>
|
41
|
-
|
42
|
-
|
50
|
+
<entry>
|
51
|
+
field_map {"MESSAGE": "log", "_PID": ["process", "pid"], "_CMDLINE": "process", "_COMM": "cmd"}
|
52
|
+
fields_strip_underscores true
|
53
|
+
fields_lowercase true
|
54
|
+
</entry>
|
43
55
|
</source>
|
44
56
|
|
45
57
|
<match kube-proxy>
|
@@ -78,19 +90,83 @@ If true reads all available journal from head, otherwise starts reading from tai
|
|
78
90
|
|
79
91
|
**`strip_underscores`**
|
80
92
|
|
93
|
+
_This parameter is deprecated and will be removed in favour of entry in v1.0._
|
94
|
+
|
81
95
|
If true strips underscores from the beginning of systemd field names.
|
82
96
|
May be useful if outputting to kibana, as underscore prefixed fields are unindexed there.
|
83
97
|
|
98
|
+
**`entry`**
|
99
|
+
|
100
|
+
Optional configuration for an embeded systemd entry filter. See the [Filter Plugin Configuration](#filter-plugin-configuration) for config reference.
|
101
|
+
|
84
102
|
**`tag`**
|
85
103
|
|
86
|
-
_Required_
|
104
|
+
_Required_
|
87
105
|
|
88
106
|
A tag that will be added to events generated by this input.
|
89
107
|
|
90
|
-
|
108
|
+
### Example
|
91
109
|
|
92
110
|
For an example of a full working setup including the plugin, [take a look at](https://github.com/assemblyline/fluentd)
|
93
111
|
|
112
|
+
## Filter Plugin Configuration
|
113
|
+
|
114
|
+
<filter kube-proxy>
|
115
|
+
@type systemd_entry
|
116
|
+
field_map {"MESSAGE": "log", "_PID": ["process", "pid"], "_CMDLINE": "process", "_COMM": "cmd"}
|
117
|
+
field_map_strict false
|
118
|
+
fields_lowercase true
|
119
|
+
fields_strip_underscores true
|
120
|
+
</filter>
|
121
|
+
|
122
|
+
**`field_map`**
|
123
|
+
|
124
|
+
Object / hash defining a mapping of source fields to destination fields. Destination fields may be existing or new user-defined fields. If multiple source fields are mapped to the same destination field, the contents of the fields will be appended to the destination field in the order defined in the mapping. A field map declaration takes the form of:
|
125
|
+
|
126
|
+
{
|
127
|
+
"<src_field1>": "<dst_field1>",
|
128
|
+
"<src_field2>": ["<dst_field1>", "<dst_field2>"],
|
129
|
+
...
|
130
|
+
}
|
131
|
+
Defaults to an empty map.
|
132
|
+
|
133
|
+
**`field_map_strict`**
|
134
|
+
|
135
|
+
If true, only destination fields from `field_map` are included in the result. Defaults to false.
|
136
|
+
|
137
|
+
**`fields_lowercase`**
|
138
|
+
|
139
|
+
If true, lowercase all non-mapped fields. Defaults to false.
|
140
|
+
|
141
|
+
**`fields_strip_underscores`**
|
142
|
+
|
143
|
+
If true, strip leading underscores from all non-mapped fields. Defaults to false.
|
144
|
+
|
145
|
+
### Example
|
146
|
+
|
147
|
+
Given a systemd journal source entry:
|
148
|
+
```
|
149
|
+
{
|
150
|
+
"_MACHINE_ID": "bb9d0a52a41243829ecd729b40ac0bce"
|
151
|
+
"_HOSTNAME": "arch"
|
152
|
+
"MESSAGE": "this is a log message",
|
153
|
+
"_PID": "123"
|
154
|
+
"_CMDLINE": "login -- root"
|
155
|
+
"_COMM": "login"
|
156
|
+
}
|
157
|
+
```
|
158
|
+
The resulting entry using the above sample configuration:
|
159
|
+
```
|
160
|
+
{
|
161
|
+
"machine_id": "bb9d0a52a41243829ecd729b40ac0bce"
|
162
|
+
"hostname": "arch",
|
163
|
+
"msg": "this is a log message",
|
164
|
+
"pid": "123"
|
165
|
+
"cmd": "login"
|
166
|
+
"process": "123 login -- root"
|
167
|
+
}
|
168
|
+
```
|
169
|
+
|
94
170
|
## Dependencies
|
95
171
|
|
96
172
|
This plugin depends on libsystemd
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "fluent/plugin/filter"
|
3
|
+
require "fluent/plugin/systemd/entry_mutator"
|
4
|
+
|
5
|
+
module Fluent
|
6
|
+
module Plugin
|
7
|
+
# Fluentd systemd/journal filter plugin
|
8
|
+
class SystemdEntryFilter < Filter
|
9
|
+
Fluent::Plugin.register_filter("systemd_entry", self)
|
10
|
+
|
11
|
+
config_param :field_map, :hash, default: {}
|
12
|
+
config_param :field_map_strict, :bool, default: false
|
13
|
+
config_param :fields_strip_underscores, :bool, default: false
|
14
|
+
config_param :fields_lowercase, :bool, default: false
|
15
|
+
|
16
|
+
def configure(conf)
|
17
|
+
super
|
18
|
+
@mutator = SystemdEntryMutator.new(**@config_root_section.to_h)
|
19
|
+
if @mutator.field_map_strict && @mutator.field_map.empty?
|
20
|
+
log.warn("`field_map_strict` set to true with empty `field_map`, expect no fields")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def filter(_tag, _time, entry)
|
25
|
+
@mutator.run(entry)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "systemd/journal"
|
2
3
|
require "fluent/plugin/input"
|
3
4
|
require "fluent/plugin/systemd/pos_writer"
|
5
|
+
require "fluent/plugin/systemd/entry_mutator"
|
4
6
|
|
5
7
|
module Fluent
|
6
8
|
module Plugin
|
@@ -9,13 +11,14 @@ module Fluent
|
|
9
11
|
|
10
12
|
helpers :timer, :storage
|
11
13
|
|
12
|
-
DEFAULT_STORAGE_TYPE = "local"
|
14
|
+
DEFAULT_STORAGE_TYPE = "local"
|
13
15
|
|
14
16
|
config_param :path, :string, default: "/var/log/journal"
|
15
17
|
config_param :filters, :array, default: []
|
16
18
|
config_param :pos_file, :string, default: nil, deprecated: "Use <storage> section with `persistent: true' instead"
|
17
19
|
config_param :read_from_head, :bool, default: false
|
18
|
-
config_param :strip_underscores, :bool, default: false
|
20
|
+
config_param :strip_underscores, :bool, default: false, deprecated: "Use <entry> section or `systemd_entry` " \
|
21
|
+
"filter plugin instead"
|
19
22
|
config_param :tag, :string
|
20
23
|
|
21
24
|
config_section :storage do
|
@@ -24,10 +27,24 @@ module Fluent
|
|
24
27
|
config_set_default :persistent, false
|
25
28
|
end
|
26
29
|
|
30
|
+
config_section :entry, param_name: "entry_opts", required: false, multi: false do
|
31
|
+
config_param :field_map, :hash, default: {}
|
32
|
+
config_param :field_map_strict, :bool, default: false
|
33
|
+
config_param :fields_strip_underscores, :bool, default: false
|
34
|
+
config_param :fields_lowercase, :bool, default: false
|
35
|
+
end
|
36
|
+
|
27
37
|
def configure(conf)
|
28
38
|
super
|
39
|
+
@journal = nil
|
29
40
|
@pos_storage = PosWriter.new(@pos_file, storage_create(usage: "positions"))
|
30
|
-
|
41
|
+
# legacy strip_underscores backwards compatibility (legacy takes
|
42
|
+
# precedence and is mutually exclusive with the entry block)
|
43
|
+
mut_opts = @strip_underscores ? { fields_strip_underscores: true } : @entry_opts.to_h
|
44
|
+
@mutator = SystemdEntryMutator.new(**mut_opts)
|
45
|
+
if @mutator.field_map_strict && @mutator.field_map.empty?
|
46
|
+
log.warn("`field_map_strict` set to true with empty `field_map`, expect no fields")
|
47
|
+
end
|
31
48
|
end
|
32
49
|
|
33
50
|
def start
|
@@ -89,17 +106,24 @@ module Fluent
|
|
89
106
|
return unless @journal || init_journal
|
90
107
|
init_journal if @journal.wait(0) == :invalidate
|
91
108
|
watch do |entry|
|
92
|
-
|
93
|
-
router.emit(@tag, Fluent::EventTime.from_time(entry.realtime_timestamp), formatted(entry))
|
94
|
-
rescue => e
|
95
|
-
log.error("Exception emitting record: #{e}")
|
96
|
-
end
|
109
|
+
emit(entry)
|
97
110
|
end
|
98
111
|
end
|
99
112
|
|
113
|
+
def emit(entry)
|
114
|
+
router.emit(@tag, Fluent::EventTime.from_time(entry.realtime_timestamp), formatted(entry))
|
115
|
+
rescue Fluent::Plugin::Buffer::BufferOverflowError => e
|
116
|
+
retries ||= 0
|
117
|
+
raise e if retries > 10
|
118
|
+
retries += 1
|
119
|
+
sleep 1.5**retries + rand(0..3)
|
120
|
+
retry
|
121
|
+
rescue => e
|
122
|
+
log.error("Exception emitting record: #{e}")
|
123
|
+
end
|
124
|
+
|
100
125
|
def formatted(entry)
|
101
|
-
|
102
|
-
Hash[entry.to_h.map { |k, v| [k.gsub(/\A_+/, ""), v] }]
|
126
|
+
@mutator.run(entry)
|
103
127
|
end
|
104
128
|
|
105
129
|
def watch
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "fluent/config/error"
|
3
|
+
|
4
|
+
module Fluent
|
5
|
+
module Plugin
|
6
|
+
# A simple stand-alone configurable mutator for systemd journal entries.
|
7
|
+
#
|
8
|
+
# Note regarding field mapping:
|
9
|
+
# The input `field_map` option is meant to have a structure that is
|
10
|
+
# intuative or logical for humans when declaring a field map.
|
11
|
+
# {
|
12
|
+
# "<source_field1>" => "<new_field1>",
|
13
|
+
# "<source_field2>" => ["<new_field1>", "<new_field2>"]
|
14
|
+
# }
|
15
|
+
# Internally the inverse of the human-friendly field_map is
|
16
|
+
# computed (and cached) upon object creation and used as a "mapped model"
|
17
|
+
# {
|
18
|
+
# "<new_field1>" => ["<source_field1>", "<source_field2>"],
|
19
|
+
# "<new_field2>" => ["<source_field2>"]
|
20
|
+
# }
|
21
|
+
class SystemdEntryMutator
|
22
|
+
|
23
|
+
Options = Struct.new(
|
24
|
+
:field_map,
|
25
|
+
:field_map_strict,
|
26
|
+
:fields_lowercase,
|
27
|
+
:fields_strip_underscores,
|
28
|
+
)
|
29
|
+
|
30
|
+
def self.default_opts
|
31
|
+
Options.new({}, false, false, false)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Constructor keyword options (all other kwargs are ignored):
|
35
|
+
# field_map - hash describing the desired field mapping in the form:
|
36
|
+
# {"<source_field>" => "<new_field>", ...}
|
37
|
+
# where `new_field` is a string or array of strings
|
38
|
+
# field_map_strict - boolean if true will only include new fields
|
39
|
+
# defined in `field_map`
|
40
|
+
# fields_strip_underscores - boolean if true will strip all leading
|
41
|
+
# underscores from non-mapped fields
|
42
|
+
# fields_lowercase - boolean if true lowercase all non-mapped fields
|
43
|
+
#
|
44
|
+
# raises `Fluent::ConfigError` for invalid options
|
45
|
+
def initialize(**options)
|
46
|
+
@opts = options_from_hash(options)
|
47
|
+
validate_options(@opts)
|
48
|
+
@map = invert_field_map(@opts.field_map)
|
49
|
+
@map_src_fields = @opts.field_map.keys
|
50
|
+
@no_transform = @opts == self.class.default_opts
|
51
|
+
end
|
52
|
+
|
53
|
+
# Expose config state as read-only instance properties of the mutator.
|
54
|
+
def method_missing(sym, *args)
|
55
|
+
return @opts[sym] if @opts.members.include?(sym)
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
# The main run method that performs all configured mutations, if any,
|
60
|
+
# against a single journal entry. Returns the mutated entry hash.
|
61
|
+
# entry - hash or `Systemd::Journal:Entry`
|
62
|
+
def run(entry)
|
63
|
+
return entry.to_h if @no_transform
|
64
|
+
return map_fields(entry) if @opts.field_map_strict
|
65
|
+
format_fields(entry, map_fields(entry))
|
66
|
+
end
|
67
|
+
|
68
|
+
# Run field mapping against a single journal entry. Returns the mutated
|
69
|
+
# entry hash.
|
70
|
+
# entry - hash or `Systemd::Journal:Entry`
|
71
|
+
def map_fields(entry)
|
72
|
+
mapped = {}
|
73
|
+
@map.each do |cstm, sysds|
|
74
|
+
vals = sysds.collect { |fld| entry[fld] }.compact
|
75
|
+
next if vals.empty? # systemd field does not exist in source entry
|
76
|
+
mapped[cstm] = vals.length == 1 ? vals[0] : vals.join(" ")
|
77
|
+
end
|
78
|
+
mapped
|
79
|
+
end
|
80
|
+
|
81
|
+
# Run field formatting (mutations applied to all non-mapped fields)
|
82
|
+
# against a single journal entry. Returns the mutated entry hash.
|
83
|
+
# entry - hash or `Systemd::Journal:Entry`
|
84
|
+
# mapped - Optional hash that represents a previously mapped entry to
|
85
|
+
# which the formatted fields will be added
|
86
|
+
def format_fields(entry, mapped = nil)
|
87
|
+
mapped ||= {}
|
88
|
+
entry.each do |fld, val|
|
89
|
+
# don't mess with explicitly mapped fields
|
90
|
+
next if @map_src_fields.include?(fld)
|
91
|
+
fld = fld.gsub(/\A_+/, "") if @opts.fields_strip_underscores
|
92
|
+
fld = fld.downcase if @opts.fields_lowercase
|
93
|
+
# account for mapping (appending) to an existing systemd field
|
94
|
+
mapped[fld] = mapped.key?(fld) ? [val, mapped[fld]].join(" ") : val
|
95
|
+
end
|
96
|
+
mapped
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# Returns a `SystemdEntryMutator::Options` struct derived from the
|
102
|
+
# elements in the supplied hash merged with the option defaults
|
103
|
+
def options_from_hash(opts)
|
104
|
+
merged = self.class.default_opts
|
105
|
+
merged.each_pair do |k, _|
|
106
|
+
merged[k] = opts[k] if opts.key?(k)
|
107
|
+
end
|
108
|
+
merged
|
109
|
+
end
|
110
|
+
|
111
|
+
def validate_options(opts)
|
112
|
+
unless validate_strings_or_empty(opts[:field_map].keys)
|
113
|
+
err = "`field_map` keys must be strings"
|
114
|
+
end
|
115
|
+
unless validate_strings_or_empty(opts[:field_map].values, true)
|
116
|
+
err = "`field_map` values must be strings or array of strings"
|
117
|
+
end
|
118
|
+
%i[field_map_strict fields_strip_underscores fields_lowercase].each do |opt|
|
119
|
+
err = "`#{opt}` must be boolean" unless [true, false].include?(opts[opt])
|
120
|
+
end
|
121
|
+
fail Fluent::ConfigError, err unless err.nil?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Validates that values in array `arr` are strings. If `nested` is true
|
125
|
+
# also allow and validate that `arr` values can be an array of strings
|
126
|
+
def validate_strings_or_empty(arr, nested = false)
|
127
|
+
return true if arr.empty?
|
128
|
+
arr.each do |v|
|
129
|
+
return true if v.is_a?(String)
|
130
|
+
if v.is_a?(Array) && nested
|
131
|
+
v.each { |nstd| return false unless nstd.is_a?(String) }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
false
|
135
|
+
end
|
136
|
+
|
137
|
+
# Compute the inverse of a human friendly field map `fm` which is what
|
138
|
+
# the mutator uses for the actual mapping. The resulting structure for
|
139
|
+
# the inverse field map hash is:
|
140
|
+
# {"<new_field_name>" => ["<source_field_name>", ...], ...}
|
141
|
+
def invert_field_map(fm)
|
142
|
+
invs = {}
|
143
|
+
fm.values.flatten.uniq.each do |cstm|
|
144
|
+
sysds = fm.select { |_, v| (v == cstm || v.include?(cstm)) }
|
145
|
+
invs[cstm] = sysds.keys
|
146
|
+
end
|
147
|
+
invs
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "fluent/plugin/input"
|
2
3
|
|
3
4
|
module Fluent
|
@@ -66,7 +67,7 @@ module Fluent
|
|
66
67
|
def write_pos
|
67
68
|
@lock.synchronize do
|
68
69
|
if @written_cursor != @cursor
|
69
|
-
file = File.open(@path, "w+",
|
70
|
+
file = File.open(@path, "w+", 0o644)
|
70
71
|
file.print @cursor
|
71
72
|
file.close
|
72
73
|
@written_cursor = @cursor
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-systemd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ed Robinson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -109,7 +109,9 @@ extra_rdoc_files: []
|
|
109
109
|
files:
|
110
110
|
- LICENCE
|
111
111
|
- README.md
|
112
|
+
- lib/fluent/plugin/filter_systemd_entry.rb
|
112
113
|
- lib/fluent/plugin/in_systemd.rb
|
114
|
+
- lib/fluent/plugin/systemd/entry_mutator.rb
|
113
115
|
- lib/fluent/plugin/systemd/pos_writer.rb
|
114
116
|
homepage: https://github.com/reevoo/fluent-plugin-systemd
|
115
117
|
licenses:
|
@@ -131,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
133
|
version: '0'
|
132
134
|
requirements: []
|
133
135
|
rubyforge_project:
|
134
|
-
rubygems_version: 2.6.
|
136
|
+
rubygems_version: 2.6.11
|
135
137
|
signing_key:
|
136
138
|
specification_version: 4
|
137
139
|
summary: Input plugin to read from systemd journal.
|