fluent-plugin-macos-log 0.0.1.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 57016186f913c0af39bac56db61c9c053bed21a1f91230bbd47e24c9636264e2
4
+ data.tar.gz: 41b000bade26ccbdcca84d65e7c624a74a144d5845ad3814935ef4151c14857c
5
+ SHA512:
6
+ metadata.gz: 04d5a09d8d5ea8181fe8d697090af30c304c1a80181d28389eba85c0293abe41e0a84d47f2f8ab62d0f274c39adb08ecbe7b4c357dac92cfe112cc50b5f60deb
7
+ data.tar.gz: 8080c62ca068e40444f8aa3c3aa265b21e428fb47f9c18bf4b464955d87bf32b754caac11ed808e6f1d9db8d1232534d73cb4514fb935f156ca4d188a45f204e
@@ -0,0 +1,143 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2.1
6
+
7
+ executors:
8
+ ruby:
9
+ docker:
10
+ - image: circleci/ruby:2.6.6-node
11
+ environment:
12
+ BUNDLER_VERSION: 2.1.4
13
+ REPO_NAME: "fluent-plugin-macos-log"
14
+ BUNDLE_PATH: "vendor/bundle"
15
+ VERSION_FILE: "version.txt"
16
+
17
+ references:
18
+ depends_cache_key: &depends_cache_key
19
+ v1-dependencies-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
20
+ fallback_repo_cache_key: &fallback_repo_cache_key
21
+ v1-dependencies-
22
+ restore_deps: &restore_deps
23
+ restore_cache:
24
+ keys:
25
+ - *depends_cache_key
26
+ - *fallback_repo_cache_key
27
+ save_deps: &save_deps
28
+ save_cache:
29
+ paths:
30
+ - ./vendor/bundle
31
+ key: *depends_cache_key
32
+ install_bundler: &install_bundler
33
+ run:
34
+ name: Install bundler
35
+ command: gem install bundler:$BUNDLER_VERSION
36
+
37
+ jobs:
38
+ build:
39
+ executor: ruby
40
+ working_directory: ~/repo
41
+ steps:
42
+ - checkout
43
+
44
+ # Download and cache dependencies
45
+ - *restore_deps
46
+ - *install_bundler
47
+ - run:
48
+ name: Install dependencies
49
+ command: bundle install --jobs=4 --retry=3
50
+
51
+ - *save_deps
52
+
53
+ # run tests!
54
+ - run:
55
+ name: run tests
56
+ command: |
57
+ mkdir /tmp/test-results
58
+ bundle exec rake test
59
+
60
+ # collect reports
61
+ - store_test_results:
62
+ path: /tmp/test-results
63
+ - store_artifacts:
64
+ path: /tmp/test-results
65
+ destination: test-results
66
+
67
+ release:
68
+ executor: ruby
69
+ working_directory: ~/repo
70
+ steps:
71
+ - add_ssh_keys:
72
+ fingerprints:
73
+ - "a5:d3:86:70:21:30:78:71:87:a7:45:34:0a:47:f6:5c"
74
+ - checkout
75
+ - *restore_deps
76
+ - *install_bundler
77
+ - run:
78
+ name: Ruby version
79
+ command: |
80
+ ruby --version
81
+ gem env version
82
+ bundle --version
83
+ - run:
84
+ name: Configure git for release
85
+ command: |
86
+ git config user.name "librato-ci"
87
+ git config user.email "tools+librato-ci-githublibrato.com"
88
+ # - run:
89
+ # name: Prepare release
90
+ # command: |
91
+ # sed -i'' 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1.\2.\3/g' $VERSION_FILE
92
+ # GITTAG=$(cat $VERSION_FILE)
93
+ # git add $VERSION_FILE
94
+ # git commit -m "[ci skip] prepare release $GITTAG"
95
+ # git push --set-upstream origin $CIRCLE_BRANCH
96
+ # git tag $GITTAG
97
+ # git push origin $GITTAG
98
+ - run:
99
+ name: Generate gem credentials
100
+ command: |
101
+ mkdir -p ~/.gem
102
+ echo -e "---\r\n:rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials
103
+ chmod 0600 ~/.gem/credentials
104
+ - run:
105
+ name: Perform build
106
+ command: |
107
+ rm -rf ${REPO_NAME}-*.gem
108
+ bundle exec gem build ${REPO_NAME}.gemspec
109
+ - run:
110
+ name: Perform publish
111
+ command: |
112
+ cat ~/.gem/credentials
113
+ bundle exec gem push ${REPO_NAME}-*.gem
114
+ - run:
115
+ name: Prepare next release version
116
+ command: |
117
+ VERSION=$(cat $VERSION_FILE | xargs)
118
+ if [[ $VERSION =~ ^(.*)(([0-9]+)\.([0-9]+)\.([0-9]+))(-.*)? ]]; then
119
+ SEMVERMAJOR=${BASH_REMATCH[3]}
120
+ SEMVERMINOR=${BASH_REMATCH[4]}
121
+ SEMVERPATCH=$(expr ${BASH_REMATCH[5]} + 1)
122
+ NEWVERSION="${SEMVERMAJOR}.${SEMVERMINOR}.${SEMVERPATCH}.beta.1"
123
+ echo "$NEWVERSION" > $VERSION_FILE
124
+ git add $VERSION_FILE Gemfile.lock
125
+ git commit -m "[ci skip] prepare for next development iteration"
126
+ git push --set-upstream origin $CIRCLE_BRANCH
127
+ fi
128
+ - run:
129
+ name: Clean credentials
130
+ command: shred -u ~/.gem/credentials
131
+ when: always
132
+
133
+ workflows:
134
+ build_test_release:
135
+ jobs:
136
+ - build
137
+ - release:
138
+ filters:
139
+ branches:
140
+ only:
141
+ - develop
142
+ requires:
143
+ - build
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ vendor/
4
+ pkg/*
5
+ .idea/
6
+ *.iml
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-macos-log.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fluent-plugin-macos-log (0.0.1.beta.1)
5
+ fluentd (>= 1.2, < 2)
6
+ yajl-ruby (~> 1.3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ concurrent-ruby (1.1.8)
12
+ cool.io (1.7.1)
13
+ fluentd (1.12.1)
14
+ bundler
15
+ cool.io (>= 1.4.5, < 2.0.0)
16
+ http_parser.rb (>= 0.5.1, < 0.7.0)
17
+ msgpack (>= 1.3.1, < 2.0.0)
18
+ serverengine (>= 2.2.2, < 3.0.0)
19
+ sigdump (~> 0.2.2)
20
+ strptime (>= 0.2.2, < 1.0.0)
21
+ tzinfo (>= 1.0, < 3.0)
22
+ tzinfo-data (~> 1.0)
23
+ yajl-ruby (~> 1.0)
24
+ http_parser.rb (0.6.0)
25
+ minitest (5.14.2)
26
+ msgpack (1.4.2)
27
+ power_assert (1.2.0)
28
+ rake (10.5.0)
29
+ serverengine (2.2.3)
30
+ sigdump (~> 0.2.2)
31
+ sigdump (0.2.4)
32
+ strptime (0.2.5)
33
+ test-unit (3.3.7)
34
+ power_assert
35
+ tzinfo (2.0.4)
36
+ concurrent-ruby (~> 1.0)
37
+ tzinfo-data (1.2021.1)
38
+ tzinfo (>= 1.0.0)
39
+ yajl-ruby (1.4.1)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ bundler (~> 2.0)
46
+ fluent-plugin-macos-log!
47
+ minitest (~> 5.0)
48
+ rake (~> 10.0)
49
+ test-unit (~> 3.2)
50
+
51
+ BUNDLED WITH
52
+ 2.1.4
data/Makefile ADDED
@@ -0,0 +1,17 @@
1
+ REPO_NAME=fluent-plugin-macos-log
2
+
3
+ bundle:
4
+ bundle install
5
+
6
+ test: bundle
7
+ bundle exec rake test
8
+
9
+ package: bundle
10
+ rm -rf ${REPO_NAME}-*.gem
11
+ bundle exec gem build ${REPO_NAME}.gemspec
12
+
13
+ deploy: package
14
+ gem install ${REPO_NAME}
15
+
16
+ release: package
17
+ bundle exec gem push ${REPO_NAME}-*.gem
data/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # Fluent::Plugin::MacOsLogInput
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/fluent-plugin-macos-log.svg)](https://badge.fury.io/rb/fluent-plugin-macos-log) [![CircleCI](https://circleci.com/gh/loggly/fluent-plugin-macos-log/tree/master.svg?style=shield)](https://circleci.com/gh/loggly/fluent-plugin-macos-log/tree/master)
4
+
5
+ ## Description
6
+
7
+ This repository contains the Fluentd MacOs unified logs input Plugin.
8
+
9
+ ## Installation
10
+
11
+ Install this gem when setting up fluentd:
12
+ ```ruby
13
+ gem install fluent-plugin-macos-log
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ### Setup
19
+
20
+ This is a process execution input plugin for Fluentd that periodically executes external `log show` command and parses log events into Fluentd's core system.
21
+ Each execution alters `start` and `end` time input parameters of log utility to slowly iterates over log data. The iteration
22
+ interval can be configured by user, but cannot be lower than 1s.
23
+
24
+ There are multiple configurations one can use:
25
+
26
+ #### Simplified Output
27
+ Uses human-readable output of the command. The process output is parsed using `regexp` parser
28
+ and logic, which combines multiple lines together. The parameter `log_line_start` defines regular expresion, which matches the
29
+ beginning of line. Anything in between will be merged into single log entry. Although the parser is `regexp`, user can select any other supported parser.
30
+ To configure this in fluentd:
31
+ ```xml
32
+ <source>
33
+ @type macoslog
34
+ tag macos
35
+ pos_file /path/to/position/file
36
+ run_interval 10s
37
+ </source>
38
+ ```
39
+
40
+ #### Detail Output
41
+ Use when more detailed output is required. It uses `ndjson` style of `log` command, which is then parsed by json parser.
42
+ To configure this in fluentd:
43
+ ```xml
44
+ <source>
45
+ @type macoslog
46
+ style ndjson
47
+ tag macos
48
+ pos_file last-starttime.log
49
+ run_interval 10s
50
+ <parse>
51
+ @type json
52
+ time_type string
53
+ time_key timestamp
54
+ time_format %Y-%m-%d %H:%M:%S.%L%z
55
+ </parse>
56
+ </source>
57
+ ```
58
+
59
+ ### Advanced Configuration
60
+ This plugin inherits Fluentd's standard input parameters.
61
+
62
+ The command used by default is `log show --style default --start @%s --end @%s` in order to combine multiple lines and iterate over
63
+ each period of time. Notice the `start` and `end` parameters use `@`, which is notation for unix timestamp format, used by plugin.
64
+
65
+ Optionally the plugin uses position file, where it records last processed timestamp. Whenever the `fluentd` process
66
+ restarts the plugin picks up from the last position. When no position files is used the plugin starts from current time
67
+ and keeps last position only in memory.
68
+
69
+ Optionally one can configure any `predicate` to filter required logs.
70
+
71
+ * `command` - external command to be executed for each interval. The command's first parameter noted ruby's `%s` as start
72
+ unix timestamp and the second `%s` for end timestamp. Default: `log show --style default --start @%s --end @%s`
73
+ * `predicate` - log filter predicate as per Apple's documentation. Default: `nil`
74
+ * `levels` - Controls what logging levels will be shown. Supported by `log` command:
75
+ * [no-]backtrace Control whether backtraces are shown
76
+ * [no-]debug Control whether "Debug" events are shown
77
+ * [no-]info Control whether "Info" events are shown
78
+ * [no-]loss Control whether message loss events are shown
79
+ * [no-]signpost Control whether signposts are shown
80
+ * `style` - Controls style of logging tool output.
81
+ * `ndjson` - single lined json format output. When used, the json parser must be configured.
82
+ * `connect_mode` - Control target IO:
83
+ * `read`: Read logs from stdio
84
+ * `read_with_stderr`: Read logs from stdio and stderr (mainly for debug).
85
+ * `parser` section - Refer these for more details about parse section. Default `regexp`
86
+ * `tag` - The tag of the output events.
87
+ * `run_interval` - The interval time between periodic program runs.
88
+ * `max_age` - The time base max age of logs to process. Default `3d`
89
+ * `pos_file` - Fluentd will record the position it last read from external command.
90
+ Don't share pos_file between in_macoslog configurations. It causes unexpected behavior e.g. corrupt pos_file content.
91
+ * `log_line_start` - Regexp of start of the log to combine multiline logs. Default: `\d+-\d+-\d+\s+\d+:\d+:\d+[^ ]+`
92
+ * `log_header_lines` - Number of header lines to skip when parsing. When `ndjson` style used the parameter refers
93
+ to number of footer lines to be skipped. Default: `1`
94
+
95
+ One can configure own parser:
96
+ ```xml
97
+ <source>
98
+ @type macoslog
99
+ tag macos
100
+ pos_file /path/to/position/file
101
+ run_interval 10s
102
+ <parse>
103
+ @type tsv
104
+ keys avg1,avg5,avg15
105
+ delimiter " "
106
+ </parse>
107
+ </source>
108
+ ```
109
+
110
+ ### Example
111
+ Example configuration for sending logs over to Loggly. The input plugin collects unified logs with filter `process == "sharingd"`
112
+ every `10s` while recording position in file `/path/to/position/file`.
113
+
114
+ It uses output [fluent-plugin-loggly](https://github.com/patant/fluent-plugin-loggly) configured in buffer mode.
115
+
116
+ ```xml
117
+ <source>
118
+ @type macoslog
119
+ predicate process == "sharingd"
120
+ tag macos
121
+ pos_file /path/to/position/file
122
+ run_interval 10s
123
+ </source>
124
+
125
+ <match macos>
126
+ type loggly_buffered
127
+ loggly_url https://logs-01.loggly.com/bulk/xxx-xxxx-xxxx-xxxxx-xxxxxxxxxx
128
+ output_include_time true
129
+ time_precision_digits 3
130
+ buffer_type file
131
+ buffer_path /path/to/buffer/file
132
+ flush_interval 10s
133
+ </match>
134
+ ```
135
+
136
+ ## Development
137
+
138
+ This plugin is targeting Ruby 2.6 and Fluentd v1.0, although it should work with older versions of both.
139
+
140
+ We have a [Makefile](Makefile) to wrap common functions and make life easier.
141
+
142
+ ### Prepare development
143
+ To install fluentd on MacOs use following ruby environment.
144
+ ```shell script
145
+ brew install rbenv ruby-build
146
+ echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.zshrc
147
+ source ~/.zshrc
148
+ rbenv install 2.6.3
149
+ rbenv global 2.6.3
150
+
151
+ gem install fluentd --no-doc
152
+ ```
153
+
154
+ Install latest bundler
155
+ ```shell script
156
+ gem install bundler
157
+ ```
158
+
159
+ ### Install Dependencies
160
+ `make bundle`
161
+
162
+ ### Test
163
+ `make test`
164
+
165
+ ### Release in [RubyGems](https://rubygems.org/gems/fluent-plugin-macos-log)
166
+ To release a new version, update the version number in the [GemSpec](fluent-plugin-macos-log.gemspec) and then, run:
167
+
168
+ `make release`
169
+
170
+ ## Contributing
171
+
172
+ Bug reports and pull requests are welcome on GitHub at: https://github.com/loggly/fluent-plugin-macos-log
173
+
174
+ # Questions/Comments?
175
+
176
+ Please [open an issue](https://github.com/loggly/fluent-plugin-macos-log/issues/new), we'd love to hear from you.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "rake/testtask"
2
+
3
+ Rake::TestTask.new(:test) do |t|
4
+ t.libs << "test"
5
+ t.libs << "lib"
6
+ t.test_files = FileList['test/**/test_*.rb']
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ version = File.read('version.txt').strip
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "fluent-plugin-macos-log"
9
+ spec.version = version
10
+ spec.authors = ["Petr Langr"]
11
+ spec.email = ["petr.langr@solarwinds.com"]
12
+
13
+ spec.summary = %q{Fluentd input plugin for MacOS unified log}
14
+ spec.description = %q{Fluentd input from MacOS unified log}
15
+ spec.homepage = "https://github.com/loggly/fluent-plugin-macos-log"
16
+ spec.license = "MIT"
17
+
18
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
20
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_dependency "fluentd", '>= 1.2', '< 2'
26
+ spec.add_dependency "yajl-ruby", '~> 1.3'
27
+
28
+ spec.add_development_dependency "bundler", "~> 2.0"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "minitest", "~> 5.0"
31
+ spec.add_development_dependency "test-unit", "~> 3.2"
32
+ end
@@ -0,0 +1,10 @@
1
+ GEM
2
+ specs:
3
+
4
+ PLATFORMS
5
+ ruby
6
+
7
+ DEPENDENCIES
8
+
9
+ BUNDLED WITH
10
+ 2.1.4
@@ -0,0 +1,71 @@
1
+
2
+ require 'fluent/plugin_helper/child_process'
3
+
4
+ module Fluent
5
+ module PluginHelper
6
+ module ChildProcess
7
+ include Fluent::PluginHelper::Thread
8
+ include Fluent::PluginHelper::Timer
9
+
10
+ def timer_process_execute(
11
+ title, command, start_timestamp, interval, time_callback,
12
+ arguments: nil, subprocess_name: nil, immediate: false, parallel: false,
13
+ mode: [:read, :write], stderr: :discard, env: {}, unsetenv: false, chdir: nil,
14
+ internal_encoding: 'utf-8', external_encoding: 'ascii-8bit', scrub: true, replace_string: nil,
15
+ wait_timeout: nil, on_exit_callback: nil, delay_seconds: 0,
16
+ &block
17
+ )
18
+ raise ArgumentError, "BUG: title must be a symbol" unless title.is_a? Symbol
19
+ raise ArgumentError, "BUG: arguments required if subprocess name is replaced" if subprocess_name && !arguments
20
+
21
+ mode ||= []
22
+ mode = [] unless block
23
+ raise ArgumentError, "BUG: invalid mode specification" unless mode.all?{|m| MODE_PARAMS.include?(m) }
24
+ raise ArgumentError, "BUG: read_with_stderr is exclusive with :read and :stderr" if mode.include?(:read_with_stderr) && (mode.include?(:read) || mode.include?(:stderr))
25
+ raise ArgumentError, "BUG: invalid stderr handling specification" unless STDERR_OPTIONS.include?(stderr)
26
+
27
+ raise ArgumentError, "BUG: number of block arguments are different from size of mode" if block && block.arity != mode.size
28
+
29
+ running = false
30
+ callback = ->(*args) {
31
+ running = true
32
+ begin
33
+ block && block.call(*args)
34
+ ensure
35
+ running = false
36
+ end
37
+ }
38
+
39
+ execute_child_process = ->(cmd) {
40
+ child_process_execute_once(
41
+ title, cmd, arguments,
42
+ subprocess_name, mode, stderr, env, unsetenv, chdir,
43
+ internal_encoding, external_encoding, scrub, replace_string,
44
+ wait_timeout, on_exit_callback,
45
+ &callback
46
+ )
47
+ }
48
+
49
+ now = Fluent::EventTime.now.to_int - delay_seconds
50
+ if immediate && start_timestamp.to_i < now
51
+ execute_child_process.call(command % [start_timestamp, now])
52
+ start_timestamp = now
53
+ time_callback.call(start_timestamp)
54
+ end
55
+
56
+ timer_execute(:child_process_execute, interval, repeat: true) do
57
+ if !parallel && running
58
+ log.warn "previous child process is still running. skipped.", title: title, command: command, arguments: arguments, interval: interval
59
+ else
60
+ end_timestamp = Fluent::EventTime.now.to_int - delay_seconds
61
+ execute_child_process.call(command % [start_timestamp, end_timestamp])
62
+ start_timestamp = end_timestamp
63
+ time_callback.call(start_timestamp)
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,199 @@
1
+
2
+ require 'fluent/plugin/input'
3
+ require 'fluent/plugin/in_exec/iterative_process'
4
+ require 'yajl'
5
+
6
+ module Fluent::Plugin
7
+ class MacOsLogInput < Fluent::Plugin::Input
8
+ Fluent::Plugin.register_input('macoslog', self)
9
+
10
+ helpers :compat_parameters, :extract, :parser, :child_process
11
+
12
+ def initialize
13
+ super
14
+ @pf_file = nil
15
+ @log_start_regex = nil
16
+ @compiled_command = nil
17
+ end
18
+
19
+ desc 'The command (program) to execute.'
20
+ config_param :command, :string, default: 'log show --start @%s --end @%s'
21
+ desc 'The unified log filter predicate as per Apple\'s documentation'
22
+ config_param :predicate, :string, default: nil
23
+ desc 'Specify connect mode to executed process'
24
+ config_param :connect_mode, :enum, list: [:read, :read_with_stderr], default: :read
25
+ desc 'Logging levels supported by Unified Logging ([no-]backtrace, [no-]debug, [no-]info, [no-]loss, [no-]signpost)'
26
+ config_param :levels, :array, default: [], value_type: :string
27
+ desc 'Output formatting of events from logging tool'
28
+ config_param :style, :enum, list: [:default, :syslog, :ndjson, :compact], default: nil
29
+
30
+ config_section :parse do
31
+ config_set_default :@type, 'regexp'
32
+ config_set_default :expression, /^(?<logtime>[\d\-]+\s*[\d\.:\+]+)\s+(?<thread>[^ ]*)\s+(?<level>[^ ]+)\s+(?<activity>[^ ]*)\s+(?<pid>[0-9]+)\s+(?<ttl>[0-9]+)\s+(?<process>[^:]*)(?:[^\:]*\:)\s*(?<message>.*)$/m
33
+ config_set_default :time_key, 'logtime'
34
+ config_set_default :time_format, '%Y-%m-%d %H:%M:%S.%L%z'
35
+ end
36
+
37
+ desc 'Tag of the output events.'
38
+ config_param :tag, :string, default: nil
39
+ desc 'The interval time between periodic program runs.'
40
+ config_param :run_interval, :time, default: nil
41
+ desc 'Fluentd will record the time it last read into this file.'
42
+ config_param :pos_file, :string, default: nil
43
+ desc 'The identifier of log line beginning used to split output by.'
44
+ config_param :log_line_start, :string, default: '\d+-\d+-\d+\s+\d+:\d+:\d+[^ ]+'
45
+ desc 'Number of header lines to be skipped. Use negative value if no header'
46
+ config_param :log_header_lines, :integer, default: 1
47
+ desc 'Max age of logs to be inputted'
48
+ config_param :max_age, :time, default: 259200 #3d
49
+
50
+ attr_reader :parser
51
+
52
+ def configure(conf)
53
+ compat_parameters_convert(conf, :parser)
54
+
55
+ super
56
+
57
+ unless @tag
58
+ raise Fluent::ConfigError, "'tag' option is required on macoslog input"
59
+ end
60
+
61
+ @compiled_command = compile_command
62
+
63
+ $log.info "MacOs log command '#{@compiled_command}'"
64
+
65
+ @parser = parser_create
66
+
67
+ unless @pos_file
68
+ $log.warn "'pos_file PATH' parameter is not set to a 'macoslog' source."
69
+ $log.warn "this parameter is highly recommended to save the position to resume from."
70
+ end
71
+
72
+ @log_start_regex = Regexp.compile("\\A#{@log_line_start}")
73
+ end
74
+
75
+ def compile_command
76
+ result = @command
77
+
78
+ if @style
79
+ result += " --style #{@style}"
80
+ elsif not result =~ /"--style"/
81
+ result += " --style default"
82
+ end
83
+
84
+ if @predicate
85
+ result += " --predicate '#{@predicate}'"
86
+ end
87
+
88
+ if @levels.length > 0
89
+ compiled_level = @levels.map { |level| "--#{level}" }.join(" ")
90
+ result += " #{compiled_level}"
91
+ end
92
+
93
+ result
94
+ end
95
+
96
+ def multi_workers_ready?
97
+ true
98
+ end
99
+
100
+ def start
101
+ super
102
+
103
+ if @pos_file
104
+ pos_file_dir = File.dirname(@pos_file)
105
+ FileUtils.mkdir_p(pos_file_dir, mode: @dir_perm) unless Dir.exist?(pos_file_dir)
106
+ @pf_file = File.open(@pos_file, File::RDWR|File::CREAT|File::BINARY, @file_perm)
107
+ @pf_file.sync = true
108
+
109
+ start = @pf_file.read.to_i
110
+ if start == 0
111
+ start = Fluent::EventTime.now.to_int
112
+ @pf_file.write(start)
113
+ end
114
+ else
115
+ start = Fluent::EventTime.now.to_int
116
+ @pf_file.write(start) if @pf_file
117
+ end
118
+
119
+ oldest = Fluent::EventTime.now.to_int - @max_age.to_i
120
+ if start < oldest
121
+ log.info "Start timestamp over max_age ", start: start, oldest: oldest
122
+ start = oldest
123
+ end
124
+
125
+ time_callback = -> (timestamp) {
126
+ if @pf_file
127
+ @pf_file.rewind
128
+ @pf_file.write(timestamp)
129
+ end
130
+ }
131
+
132
+ timer_process_execute(:exec_input,
133
+ @compiled_command,
134
+ start, @run_interval,
135
+ time_callback,
136
+ delay_seconds: 1,
137
+ immediate: true, mode: [@connect_mode], &method(:run))
138
+ end
139
+
140
+ def shutdown
141
+ @pf_file.close if @pf_file
142
+
143
+ super
144
+ end
145
+
146
+ def run(io)
147
+ unless io.eof
148
+ if @style == :ndjson
149
+ parse_line_json(io)
150
+ else
151
+ parse_timestamp_base(io)
152
+ end
153
+ end
154
+ end
155
+
156
+ def parse_line_json(io)
157
+ logs = Queue.new
158
+ io.each_line.with_index do |line,index|
159
+ logs.push(line.chomp("\n"))
160
+ if index >= @log_header_lines
161
+ @parser.parse(logs.pop, &method(:on_record))
162
+ end
163
+ end
164
+ end
165
+
166
+ def parse_timestamp_base(io)
167
+ log = ""
168
+ io.each_line.with_index do |line,index|
169
+ # Skips log header
170
+ if index >= @log_header_lines
171
+ if line =~ @log_start_regex
172
+ if log.empty?
173
+ log = line
174
+ else
175
+ @parser.parse(log.chomp("\n"), &method(:on_record))
176
+ log = line
177
+ end
178
+ else
179
+ log += line
180
+ end
181
+ end
182
+ end
183
+
184
+ unless log.empty?
185
+ @parser.parse(log.chomp("\n"), &method(:on_record))
186
+ end
187
+ end
188
+
189
+ def on_record(time, record)
190
+ tag = extract_tag_from_record(record)
191
+ tag ||= @tag
192
+ time ||= extract_time_from_record(record) || Fluent::EventTime.now
193
+ router.emit(tag, time, record)
194
+ rescue => e
195
+ log.error "macoslog failed to emit", tag: tag, record: Yajl.dump(record), error: e
196
+ router.emit_error_event(tag, time, record, e) if tag && time && record
197
+ end
198
+ end
199
+ end
data/version.txt ADDED
@@ -0,0 +1 @@
1
+ 0.0.1.beta.1
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-macos-log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta.1
5
+ platform: ruby
6
+ authors:
7
+ - Petr Langr
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: yajl-ruby
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.3'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.3'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '10.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '10.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: minitest
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '5.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '5.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: test-unit
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.2'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.2'
103
+ description: Fluentd input from MacOS unified log
104
+ email:
105
+ - petr.langr@solarwinds.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - ".circleci/config.yml"
111
+ - ".gitignore"
112
+ - Gemfile
113
+ - Gemfile.lock
114
+ - Makefile
115
+ - README.md
116
+ - Rakefile
117
+ - fluent-plugin-macos-log.gemspec
118
+ - fluent-plugin-macos-log.gemspec.lock
119
+ - lib/fluent/plugin/in_exec/iterative_process.rb
120
+ - lib/fluent/plugin/in_macoslog.rb
121
+ - version.txt
122
+ homepage: https://github.com/loggly/fluent-plugin-macos-log
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">"
138
+ - !ruby/object:Gem::Version
139
+ version: 1.3.1
140
+ requirements: []
141
+ rubygems_version: 3.0.3
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Fluentd input plugin for MacOS unified log
145
+ test_files: []