telegraf 0.4.0 → 0.8.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 880b5d95e2fb34e2f1f03d8d20b0cb9fca7617ef
4
- data.tar.gz: d78b0b208c7c3fe10fa63a9ae99d9ae6cf3c1de1
2
+ SHA256:
3
+ metadata.gz: d24537357d52b68f806f668f2e356a2272f5a2964050051827fed20afcf775b2
4
+ data.tar.gz: c6cfdaa89a5cd249dc1533c7aedda8237157e9778a42e501cc7d26b439cdcaef
5
5
  SHA512:
6
- metadata.gz: 2eb66afb4ab9d6f23107b31f5a2ebe7e669eafd932e582bde65bb4a474f87a061ffd991a913e7177f7bd216386e19da63d470951c42074f66d1aeb1a450faf2c
7
- data.tar.gz: 7a00b60bd44a4fb37236a76b4738301ae41b47510a01b5e8d40c9156ad1f4948ab72da1790a8804d5b251005a93fd7c306efd7e801ba6025671b9d2c4e269baf
6
+ metadata.gz: '085618264388f4883a978265487b0c5c7659297e4db42c04924281ed96e99fabb0ba20f0d4e4294237e5bed48bbae298a40a5c395e8d3b3ed48d9ac1a1db765a'
7
+ data.tar.gz: 825e81ddf41b25254b1d6a048223dda4e840a42171303a8080ed27e03d250ff5e130c4e6e348472cd6c3618c9eff848f5db1324e7b04df4d62990addfa214577
@@ -0,0 +1,8 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ charset = utf-8
7
+ trim_trailing_whitespace = true
8
+ insert_final_newline = true
data/.gitignore CHANGED
@@ -1,9 +1,12 @@
1
+ /_yardoc/
1
2
  /.bundle/
2
3
  /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
4
  /coverage/
6
5
  /doc/
6
+ /Gemfile.lock
7
+ /gemfiles/.bundle/
8
+ /gemfiles/*.lock
9
+ /log/
7
10
  /pkg/
8
11
  /spec/reports/
9
12
  /tmp/
@@ -1,53 +1,70 @@
1
1
  AllCops:
2
2
  Include:
3
3
  - '**/*.rb'
4
- TargetRubyVersion: 2.4
4
+ TargetRubyVersion: 2.5
5
5
 
6
- Metrics/BlockLength:
7
- Exclude:
8
- - 'spec/**/*_spec.rb'
9
-
10
- Metrics/LineLength:
11
- Exclude:
12
- - 'spec/**/*_spec.rb'
13
6
 
14
- Style/AlignParameters:
7
+ Layout/ArgumentAlignment:
15
8
  EnforcedStyle: with_fixed_indentation
16
9
 
17
- Style/BracesAroundHashParameters:
18
- EnforcedStyle: context_dependent
19
-
20
- Style/SpaceInsideHashLiteralBraces:
21
- EnforcedStyle: no_space
10
+ Layout/CaseIndentation:
11
+ EnforcedStyle: end
12
+ IndentOneStep: true
13
+ SupportedStyles:
14
+ - case
15
+ - end
22
16
 
23
- Style/RaiseArgs:
24
- EnforcedStyle: compact
17
+ Layout/FirstHashElementIndentation:
18
+ EnforcedStyle: consistent
25
19
 
26
- Style/Documentation:
27
- Enabled: false
20
+ Layout/LineLength:
21
+ Exclude:
22
+ - spec/**/*_spec.rb
28
23
 
29
- Style/SpaceInsideBlockBraces:
24
+ Layout/SpaceInsideBlockBraces:
30
25
  EnforcedStyle: space
31
26
  EnforcedStyleForEmptyBraces: no_space
32
27
  SpaceBeforeBlockParameters: false
33
28
 
34
- Style/SignalException:
35
- EnforcedStyle: only_raise
29
+ Layout/SpaceInsideHashLiteralBraces:
30
+ EnforcedStyle: no_space
36
31
 
37
- Style/CaseIndentation:
38
- EnforcedStyle: end
39
- SupportedStyles:
40
- - case
41
- - end
42
- IndentOneStep: true
43
32
 
44
- Style/ClassAndModuleChildren:
33
+ Metrics/AbcSize:
34
+ Enabled: false
35
+
36
+ Metrics/BlockLength:
37
+ Exclude:
38
+ - spec/**/*_spec.rb
39
+
40
+ Metrics/MethodLength:
45
41
  Enabled: false
46
42
 
47
- Style/TrivialAccessors:
48
- AllowPredicates: true
49
43
 
50
- Style/FileName:
44
+ Naming/FileName:
51
45
  Exclude:
52
46
  - Rakefile
53
47
  - Gemfile
48
+
49
+
50
+ Style/ClassAndModuleChildren:
51
+ Enabled: false
52
+
53
+ Style/Documentation:
54
+ Enabled: false
55
+
56
+ Style/HashEachMethods:
57
+ Enabled: false
58
+
59
+ Style/HashTransformKeys:
60
+ Enabled: false
61
+
62
+ Style/HashTransformValues:
63
+ Enabled: false
64
+
65
+ Style/RescueModifier:
66
+ Exclude:
67
+ - spec/**/*_spec.rb
68
+
69
+ Style/TrivialAccessors:
70
+ AllowPredicates: true
@@ -1,8 +1,15 @@
1
1
  sudo: false
2
- dist: trusty
2
+ dist: bionic
3
3
  language: ruby
4
4
  rvm:
5
- - 2.4.1
6
- - 2.3.4
7
- before_install:
8
- - gem install bundler -v 1.15.1
5
+ - 2.7.0
6
+ - 2.6.5
7
+ - 2.5.7
8
+ gemfile:
9
+ - gemfiles/rails_5.0.gemfile
10
+ - gemfiles/rails_5.1.gemfile
11
+ - gemfiles/rails_5.2.gemfile
12
+ - gemfiles/rails_6.0.gemfile
13
+ - gemfiles/rack_2.0.gemfile
14
+ - gemfiles/rack_2.1.gemfile
15
+ - gemfiles/rack_2.2.gemfile
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise "rails-5.0" do
4
+ group :test do
5
+ gem "rails", "~> 5.0.0"
6
+ end
7
+ end
8
+
9
+ appraise "rails-5.1" do
10
+ group :test do
11
+ gem "rails", "~> 5.1.0"
12
+ end
13
+ end
14
+
15
+ appraise "rails-5.2" do
16
+ group :test do
17
+ gem "rails", "~> 5.2.0"
18
+ end
19
+ end
20
+
21
+ appraise "rails-6.0" do
22
+ group :test do
23
+ gem "rails", "~> 6.0.0"
24
+ end
25
+ end
26
+
27
+ appraise "rack-2.0" do
28
+ group :test do
29
+ gem "rack", "~> 2.0.0"
30
+ end
31
+ end
32
+
33
+ appraise "rack-2.1" do
34
+ group :test do
35
+ gem "rack", "~> 2.1.0"
36
+ end
37
+ end
38
+
39
+ appraise "rack-2.2" do
40
+ group :test do
41
+ gem "rack", "~> 2.2.0"
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.8.0] - 2020-12-02
8
+ ### Added
9
+ - ActiveJob instrumentation (#10)
10
+
11
+ ## [0.7.0] - 2020-05-07
12
+ ### Added
13
+ - Sidekiq middleware (#8)
14
+
15
+ ## [0.6.1] - 2020-04-01
16
+ ### Fixed
17
+ - Fix type in instrumentation option (#7)
18
+
19
+ ## [0.6.0] - 2020-03-31
20
+ ### Added
21
+ - New Rack middleware and Rails plugin to collect request events (#5)
22
+
23
+ ## 0.5.0
24
+ ### Changed
25
+ - Remove `influxdb` not unnecessarily restrict users needing a specific influxdb client.
26
+
27
+ [0.7.0]: https://github.com/:jgraichen/telegraf-ruby/compare/v0.6.1...v0.7.0
28
+ [0.6.1]: https://github.com/:jgraichen/telegraf-ruby/compare/v0.6.0...v0.6.1
29
+ [0.6.0]: https://github.com/:jgraichen/telegraf-ruby/compare/v0.5.0...v0.6.0
data/Gemfile CHANGED
@@ -4,3 +4,18 @@ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in telegraf.gemspec
6
6
  gemspec
7
+
8
+ gem 'rake'
9
+ gem 'rspec', '~> 3.8'
10
+ gem 'rubocop', '~> 0.80.0'
11
+
12
+ group :test do
13
+ gem 'rack'
14
+ gem 'rails'
15
+ gem 'sidekiq', '~> 6.0'
16
+ end
17
+
18
+ group :development do
19
+ gem 'appraisal'
20
+ gem 'rake-release', '~> 1.2'
21
+ end
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Telegraf
2
2
 
3
- Minimal gem to send metrics to a local telegraf agent.
3
+ Send events to a local [Telegraf](https://github.com/influxdata/telegraf) agent or anything that can receive the InfluxDB line protocol.
4
+
5
+ It further includes plugins for Rack, Rails and Sidekiq to collect request events. See plugin usage details below.
6
+
7
+ This gem only uses the line protocol from the `influxdb` gem and does not depend on any specific version. This may break in the future but does not restrict you in using a your preferred `influxdb` gem version.
4
8
 
5
9
  ## Installation
6
10
 
@@ -16,20 +20,19 @@ Or install it yourself as:
16
20
 
17
21
  $ gem install telegraf
18
22
 
19
- ## Usage
23
+ ## Usage as a library
20
24
 
21
25
  Configure telegraf socket listener e.g.:
22
26
 
23
27
  ```
24
28
  [[inputs.socket_listener]]
25
- service_address = "unix:/run/telegraf/telegraf.sock"
26
- # service_address = "tcp://localhost:8094"
29
+ service_address = "udp://localhost:8094"
27
30
 
28
31
  ```
29
32
 
30
33
  ```ruby
31
- telegraf = Telegraf::Agent.new 'unix:/run/telegraf/telegraf.sock'
32
- # telegraf = Telegraf::Agent.new 'tcp://localhost:8094'
34
+ telegraf = Telegraf::Agent.new 'udp://localhost:8094'
35
+ telegraf = Telegraf::Agent.new # default: 'udp://localhost:8094'
33
36
 
34
37
  telegraf.write('demo',
35
38
  tags: {tag_a: 'A', tag_b: 'B'},
@@ -46,9 +49,82 @@ There is not buffer or batch handling, nor connection pooling or keep alive. Eac
46
49
 
47
50
  There is no exception handling.
48
51
 
52
+ ## Using the Rack and Rails plugins
53
+
54
+ This gem include a Rails plugin and middlewares for Rack and Sidekiq to collect request events. They need to be explicitly required to be used:
55
+
56
+ ### Rack
57
+
58
+ ```ruby
59
+ require "telegraf/rack"
60
+
61
+ agent = ::Telegraf::Agent.new
62
+ use ::Telegraf::Rack.new(series: 'rack', agent: agent, tags: {global: 'tag'})
63
+ ```
64
+
65
+ See middleware [class documentation](lib/telegraf/rack.rb) for more details.
66
+
67
+ The Rack middleware supports parsing the `X-Request-Start: t=<timestamp>` header expecting a fractional (UTC) timestamp when the request has been started or first received by e.g. a load balancer. An additional value `queue_ms` with the queue time will be included.
68
+
69
+ ### Rails
70
+
71
+ The Rails plugin needs to required, too, but by default automatically installs required components (Rack, Sidekiq and Rails-specific instrumentation).
72
+
73
+ ```ruby
74
+ # e.g. in application.rb
75
+
76
+ require "telegraf/rails"
77
+
78
+ class MyApplication > ::Rails::Application
79
+ # Configure receiver
80
+ config.telegraf.connect = "udp://localhost:9084"
81
+
82
+ # By default the Rack middleware to collect events is installed
83
+ config.telegraf.rack.enabled = true
84
+ config.telegraf.rack.series = "requests"
85
+ config.telegraf.rack.tags = {}
86
+
87
+ # These are the default settings when Sidekiq is detected
88
+ config.telegraf.sidekiq.enabled = true
89
+ config.telegraf.sidekiq.series = "sidekiq"
90
+ config.telegraf.sidekiq.tags = {}
91
+
92
+ # Additionally the application is instrumented to tag events with
93
+ # controller and action as well as to collect app, database and view timings
94
+ config.telegraf.instrumentation = true
95
+ end
96
+ ```
97
+
98
+ Received event example:
99
+
100
+ ```
101
+ requests,action=index,controller=TestController,instance=TestController#index,method=GET,status=200 db_ms=0.0,view_ms=2.6217450003969134,action_ms=2.702335,app_ms=4.603561000294576,send_ms=0.09295000018028077,request_ms=4.699011000411701,queue_ms=0.00003000028323014
102
+ ```
103
+
104
+ See the various classes' documentation for more details on the collected tags and values:
105
+ - [Rack middleware](lib/telegraf/rack.rb)
106
+ - [Rails plugin](lib/telegraf/railtie.rb)
107
+ - [Sidekiq middleware](lib/telegraf/sidekiq.rb)
108
+
109
+ ### Sidekiq
110
+
111
+ ```ruby
112
+ require "telegraf/sidekiq"
113
+
114
+ agent = ::Telegraf::Agent.new
115
+ Sidekiq.configure_server do |config|
116
+ config.server_middleware do |chain|
117
+ chain.add ::Telegraf::Sidekiq::Middleware, agent: agent, series: 'background', tags: {global: 'tag'}
118
+ end
119
+ end
120
+ ```
121
+
122
+ See middleware [class documentation](lib/telegraf/sidekiq.rb) for more details.
123
+
124
+
49
125
  ## License
50
126
 
51
- Copyright (C) 2017 Jan Graichen
127
+ Copyright (C) 2017-2020 Jan Graichen
52
128
 
53
129
  This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
54
130
 
data/Rakefile CHANGED
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
3
+ require 'rake/release/task'
4
4
  require 'rspec/core/rake_task'
5
5
 
6
+ Rake::Release::Task.new do |spec|
7
+ spec.sign_tag = true
8
+ end
9
+
6
10
  RSpec::Core::RakeTask.new(:spec)
7
11
 
8
12
  task default: :spec
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "rspec", "~> 3.8"
7
+ gem "rubocop", "~> 0.80.0"
8
+
9
+ group :test do
10
+ gem "rack", "~> 2.0.0"
11
+ gem "rails"
12
+ gem "sidekiq", "~> 6.0"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal"
17
+ gem "rake-release", "~> 1.2"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "rspec", "~> 3.8"
7
+ gem "rubocop", "~> 0.80.0"
8
+
9
+ group :test do
10
+ gem "rack", "~> 2.1.0"
11
+ gem "rails"
12
+ gem "sidekiq", "~> 6.0"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal"
17
+ gem "rake-release", "~> 1.2"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "rspec", "~> 3.8"
7
+ gem "rubocop", "~> 0.80.0"
8
+
9
+ group :test do
10
+ gem "rack", "~> 2.2.0"
11
+ gem "rails"
12
+ gem "sidekiq", "~> 6.0"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal"
17
+ gem "rake-release", "~> 1.2"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "rspec", "~> 3.8"
7
+ gem "rubocop", "~> 0.80.0"
8
+
9
+ group :test do
10
+ gem "rack"
11
+ gem "rails", "~> 5.0.0"
12
+ gem "sidekiq", "~> 6.0"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal"
17
+ gem "rake-release", "~> 1.2"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "rspec", "~> 3.8"
7
+ gem "rubocop", "~> 0.80.0"
8
+
9
+ group :test do
10
+ gem "rack"
11
+ gem "rails", "~> 5.1.0"
12
+ gem "sidekiq", "~> 6.0"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal"
17
+ gem "rake-release", "~> 1.2"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "rspec", "~> 3.8"
7
+ gem "rubocop", "~> 0.80.0"
8
+
9
+ group :test do
10
+ gem "rack"
11
+ gem "rails", "~> 5.2.0"
12
+ gem "sidekiq", "~> 6.0"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal"
17
+ gem "rake-release", "~> 1.2"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "rspec", "~> 3.8"
7
+ gem "rubocop", "~> 0.80.0"
8
+
9
+ group :test do
10
+ gem "rack"
11
+ gem "rails", "~> 6.0.0"
12
+ gem "sidekiq", "~> 6.0"
13
+ end
14
+
15
+ group :development do
16
+ gem "appraisal"
17
+ gem "rake-release", "~> 1.2"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegraf
4
+ # Telegraf::ActiveJob
5
+ #
6
+ # This class collects ActiveJob queue metrics and sends them to telegraf.
7
+ #
8
+ #
9
+ # Tags:
10
+ #
11
+ # * `queue`:
12
+ # The queue this job landed on.
13
+ #
14
+ # * `job`:
15
+ # The name of the job class that was executed.
16
+ #
17
+ # * `errors`:
18
+ # Whether or not this job errored.
19
+ #
20
+ #
21
+ # Values:
22
+ #
23
+ # * `app_ms`:
24
+ # Total job processing time.
25
+ #
26
+ class ActiveJob
27
+ def initialize(agent:, series: 'active_job', tags: {})
28
+ @agent = agent
29
+ @series = series.to_s.freeze
30
+ @tags = tags.freeze
31
+ end
32
+
33
+ def call(_name, start, finish, _id, payload)
34
+ job = payload[:job]
35
+
36
+ @agent.write(
37
+ @series,
38
+ tags: {
39
+ **@tags,
40
+ job: job.class.name,
41
+ queue: job.queue_name,
42
+ errors: payload.key?(:exception_object)
43
+ },
44
+ values: {
45
+ app_ms: ((finish - start) * 1000.0) # milliseconds
46
+ }
47
+ )
48
+ end
49
+ end
50
+ end
@@ -2,19 +2,19 @@
2
2
 
3
3
  module Telegraf
4
4
  class Agent
5
- DEFAULT_URI = 'udp://localhost:8094'
5
+ DEFAULT_CONNECTION = 'udp://localhost:8094'
6
6
 
7
7
  attr_reader :uri
8
8
  attr_reader :logger
9
9
 
10
- def initialize(uri = DEFAULT_CONNECTION, logger: nil)
11
- @uri = URI.parse(uri)
10
+ def initialize(uri = nil, logger: nil)
11
+ @uri = URI.parse(uri || DEFAULT_CONNECTION)
12
12
  @logger = logger
13
13
  end
14
14
 
15
- def write(*args)
16
- write!(*args)
17
- rescue => e
15
+ def write(*args, **kwargs)
16
+ write!(*args, **kwargs)
17
+ rescue StandardError => e
18
18
  logger&.error('telegraf') do
19
19
  e.to_s + e.backtrace.join("\n")
20
20
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack'
4
+
5
+ module Telegraf
6
+ # Telegraf::Rack
7
+ #
8
+ # This rack middleware collects request metrics and sends them to the telegraf
9
+ # agent. A `Point` data structure is added to the Rack environment to assign
10
+ # custom tags and values. This point can be accessed using the environment key
11
+ # defined in `::Telegraf::Rack::FIELD_NAME`.
12
+ #
13
+ # Example:
14
+ #
15
+ # if (point = request.env[::Telegraf::Rack::FIELD_NAME])
16
+ # point.tags[:tag] = 'tag'
17
+ # point.values[:value] = 10
18
+ # end
19
+ #
20
+ #
21
+ # Tags:
22
+ #
23
+ # * `status`:
24
+ # Response status unless request errored
25
+ #
26
+ #
27
+ # Values:
28
+ #
29
+ # * `request_ms`:
30
+ # Total request processing time including response sending.
31
+ #
32
+ # * `app_ms`:
33
+ # Total application processing time.
34
+ #
35
+ # * `send_ms`:
36
+ # Time took to send the response body.
37
+ #
38
+ # * `queue_ms`:
39
+ # Queue time calculated from a `X-Request-Start` header if present. The
40
+ # header is expected to be formatted like this `t=<timestamp>` and
41
+ # contain a floating point timestamp in seconds.
42
+ #
43
+ class Rack
44
+ FIELD_NAME = 'telegraf.rack.point'
45
+ HEADER_REGEX = /t=(\d+(\.\d+)?)/.freeze
46
+
47
+ Point = Struct.new(:tags, :values)
48
+
49
+ def initialize(app, agent:, series: 'rack', tags: {}, logger: nil)
50
+ @app = app
51
+ @tags = tags.freeze
52
+ @agent = agent
53
+ @series = series.to_s.freeze
54
+ @logger = logger
55
+ end
56
+
57
+ def call(env)
58
+ if (request_start = extract_request_start(env))
59
+ queue_ms = (::Time.now.utc - request_start) * 1000 # milliseconds
60
+ end
61
+
62
+ rack_start = ::Rack::Utils.clock_time
63
+ point = env[FIELD_NAME] = Point.new(@tags.dup, {})
64
+ point.values[:queue_ms] = queue_ms if queue_ms
65
+
66
+ begin
67
+ begin
68
+ status, headers, body = @app.call(env)
69
+ ensure
70
+ point.tags[:status] ||= status || -1
71
+ point.values[:app_ms] = \
72
+ (::Rack::Utils.clock_time - rack_start) * 1000 # milliseconds
73
+ end
74
+
75
+ send_start = ::Rack::Utils.clock_time
76
+ proxy = ::Rack::BodyProxy.new(body) do
77
+ point.values[:send_ms] = \
78
+ (::Rack::Utils.clock_time - send_start) * 1000 # milliseconds
79
+
80
+ finish(env, point, rack_start)
81
+ end
82
+
83
+ [status, headers, proxy]
84
+ ensure
85
+ finish(env, point, rack_start) unless proxy
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def finish(env, point, rack_start)
92
+ point.values[:request_ms] = \
93
+ (::Rack::Utils.clock_time - rack_start) * 1000 # milliseconds
94
+
95
+ @agent.write(@series, tags: point.tags, values: point.values)
96
+ rescue StandardError => e
97
+ (@logger || env[::Rack::RACK_LOGGER])&.error(e)
98
+ end
99
+
100
+ def extract_request_start(env)
101
+ return unless env.key?('HTTP_X_REQUEST_START')
102
+
103
+ if (m = HEADER_REGEX.match(env['HTTP_X_REQUEST_START']))
104
+ ::Time.at(m[1].to_f).utc
105
+ end
106
+ rescue FloatDomainError
107
+ # Ignore obscure floats in Time.at (e.g. infinity)
108
+ false
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'telegraf/railtie'
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails'
4
+ require 'telegraf/active_job'
5
+ require 'telegraf/rack'
6
+ require 'telegraf/sidekiq'
7
+
8
+ module Telegraf
9
+ # Telegraf::Railtie
10
+ #
11
+ # This Rails plugin installs the rack middleware and adds intrumentation to
12
+ # enrich the data point with additional tags an values.
13
+ #
14
+ # These include the following tags:
15
+ #
16
+ # * `action`
17
+ # The controller action, e.g. `index`.
18
+ #
19
+ # * `controller`
20
+ # The controller class name, e.g. `API::UsersController`.
21
+ #
22
+ # * `instance`
23
+ # A combination of the controller class and the action, e.g.
24
+ # `API::UsersController#index`.
25
+ #
26
+ # * `method`
27
+ # The request method, e.g. `GET`.
28
+ #
29
+ # Additional collected values are:
30
+ #
31
+ # * `db_ms`
32
+ # Time spend with database operations in milliseconds.
33
+ #
34
+ # * `view_ms`
35
+ # Time spend with rendering views in milliseconds.
36
+ #
37
+ # * `action_ms`
38
+ # Total time spend in a Rails action in milliseconds.
39
+ #
40
+ # These additional tags and values are collection from the
41
+ # `process_action.action_controller` events usings Rails instrumentation.
42
+ #
43
+ class Railtie < ::Rails::Railtie
44
+ config.telegraf = ::ActiveSupport::OrderedOptions.new
45
+
46
+ # Connect URI or tuple
47
+ config.telegraf.connect = ::Telegraf::Agent::DEFAULT_CONNECTION
48
+
49
+ # Install Rack middlewares
50
+ config.telegraf.rack = ::ActiveSupport::OrderedOptions.new
51
+ config.telegraf.rack.enabled = true
52
+ config.telegraf.rack.series = 'requests'
53
+ config.telegraf.rack.tags = {}
54
+
55
+ # Install request instrumentation
56
+ config.telegraf.instrumentation = true
57
+
58
+ # Install ActiveJob instrumentation
59
+ config.telegraf.active_job = ::ActiveSupport::OrderedOptions.new
60
+ config.telegraf.active_job.enabled = defined?(::ActiveJob)
61
+ config.telegraf.active_job.series = 'active_job'
62
+ config.telegraf.active_job.tags = {}
63
+
64
+ # Install Sidekiq middleware
65
+ config.telegraf.sidekiq = ::ActiveSupport::OrderedOptions.new
66
+ config.telegraf.sidekiq.enabled = defined?(::Sidekiq)
67
+ config.telegraf.sidekiq.series = 'sidekiq'
68
+ config.telegraf.sidekiq.tags = {}
69
+
70
+ initializer 'telegraf.agent' do |app|
71
+ app.config.telegraf.agent ||= begin
72
+ ::Telegraf::Agent.new \
73
+ app.config.telegraf.connect,
74
+ logger: Rails.logger
75
+ end
76
+ end
77
+
78
+ initializer 'telegraf.rack' do |app|
79
+ next unless app.config.telegraf.rack.enabled
80
+
81
+ app.config.middleware.insert 0, Telegraf::Rack, \
82
+ agent: app.config.telegraf.agent,
83
+ series: app.config.telegraf.rack.series,
84
+ tags: app.config.telegraf.rack.tags,
85
+ logger: Rails.logger
86
+ end
87
+
88
+ initializer 'telegraf.instrumentation' do |app|
89
+ next unless app.config.telegraf.instrumentation
90
+
91
+ ActiveSupport::Notifications.subscribe(
92
+ 'process_action.action_controller'
93
+ ) do |_name, start, finish, _id, payload|
94
+ point = payload[:headers].env[::Telegraf::Rack::FIELD_NAME]
95
+ next unless point
96
+
97
+ point.tags[:action] = payload[:action]
98
+ point.tags[:controller] = payload[:controller]
99
+ point.tags[:instance] = "#{payload[:controller]}##{payload[:action]}"
100
+ point.tags[:method] = payload[:method]
101
+
102
+ point.values[:db_ms] = payload[:db_runtime].to_f
103
+ point.values[:view_ms] = payload[:view_runtime].to_f
104
+ point.values[:action_ms] = ((finish - start) * 1000.0) # milliseconds
105
+ end
106
+ end
107
+
108
+ initializer 'telegraf.active_job' do |app|
109
+ next unless app.config.telegraf.active_job.enabled
110
+
111
+ ActiveSupport::Notifications.subscribe(
112
+ 'perform.active_job',
113
+ Telegraf::ActiveJob.new(
114
+ agent: app.config.telegraf.agent,
115
+ series: app.config.telegraf.active_job.series,
116
+ tags: app.config.telegraf.active_job.tags
117
+ )
118
+ )
119
+ end
120
+
121
+ initializer 'telegraf.sidekiq' do |app|
122
+ next unless app.config.telegraf.sidekiq.enabled
123
+
124
+ ::Sidekiq.configure_server do |config|
125
+ config.server_middleware do |chain|
126
+ chain.add Telegraf::Sidekiq::Middleware, \
127
+ agent: app.config.telegraf.agent,
128
+ series: app.config.telegraf.sidekiq.series,
129
+ tags: app.config.telegraf.sidekiq.tags
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack'
4
+
5
+ module Telegraf
6
+ module Sidekiq
7
+ # Telegraf::Sidekiq::Middleware
8
+ #
9
+ # This Sidekiq middleware collects queue metrics and sends them to telegraf.
10
+ #
11
+ #
12
+ # Tags:
13
+ #
14
+ # * `type`:
15
+ # One of "job" or "scheduled_job".
16
+ #
17
+ # * `queue`:
18
+ # The queue this job landed on.
19
+ #
20
+ # * `worker`:
21
+ # The name of the worker class that was executed.
22
+ #
23
+ # * `errors`:
24
+ # Whether or not this job errored.
25
+ #
26
+ # * `retry`:
27
+ # Whether or not this execution was a retry of a previously failed one.
28
+ #
29
+ #
30
+ # Values:
31
+ #
32
+ # * `app_ms`:
33
+ # Total worker processing time.
34
+ #
35
+ # * `queue_ms`:
36
+ # How long did this job wait in the queue before being processed?
37
+ # Only present for "normal" (async) jobs (with tag `type` of "job").
38
+ #
39
+ class Middleware
40
+ def initialize(agent:, series: 'sidekiq', tags: {})
41
+ @agent = agent
42
+ @series = series.to_s.freeze
43
+ @tags = tags.freeze
44
+ end
45
+
46
+ def call(worker, job, queue)
47
+ job_start = ::Time.now.utc
48
+
49
+ tags = {
50
+ **@tags,
51
+ type: 'job',
52
+ errors: true,
53
+ retry: job.key?('retried_at'),
54
+ queue: queue,
55
+ worker: worker.class.name
56
+ }
57
+
58
+ values = {
59
+ retry_count: job['retry_count']
60
+ }.compact
61
+
62
+ # The "enqueued_at" key is not present for scheduled jobs.
63
+ # See https://github.com/mperham/sidekiq/wiki/Job-Format.
64
+ if job.key?('enqueued_at')
65
+ enqueued_at = ::Time.at(job['enqueued_at'].to_f).utc
66
+ values[:queue_ms] = (job_start - enqueued_at) * 1000 # milliseconds
67
+ end
68
+
69
+ # The "at" key is only present for scheduled jobs.
70
+ tags[:type] = 'scheduled_job' if job.key?('at')
71
+
72
+ begin
73
+ yield
74
+
75
+ # If we get here, this was a successful execution
76
+ tags[:errors] = false
77
+ ensure
78
+ job_stop = ::Time.now.utc
79
+
80
+ values[:app_ms] = (job_stop - job_start) * 1000 # milliseconds
81
+
82
+ @agent.write(
83
+ @series, tags: tags, values: values
84
+ )
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -3,7 +3,7 @@
3
3
  module Telegraf
4
4
  module VERSION
5
5
  MAJOR = 0
6
- MINOR = 4
6
+ MINOR = 8
7
7
  PATCH = 0
8
8
  STAGE = nil
9
9
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.').freeze
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
 
14
14
  spec.summary = 'Metric Reporter to local telegraf agent'
15
15
  spec.description = 'Metric Reporter to local telegraf agent'
16
- spec.homepage = 'https://github.com/jgraichen/ruby-telegraf'
16
+ spec.homepage = 'https://github.com/jgraichen/telegraf-ruby'
17
17
  spec.license = 'LGPLv3'
18
18
 
19
19
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -24,9 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
25
25
  spec.require_paths = ['lib']
26
26
 
27
- spec.add_dependency 'influxdb', '~> 0.3.15'
27
+ spec.add_dependency 'influxdb'
28
28
 
29
- spec.add_development_dependency 'bundler', '~> 1.15'
30
- spec.add_development_dependency 'rake', '~> 12.0'
31
- spec.add_development_dependency 'rspec', '~> 3.0'
29
+ spec.add_development_dependency 'bundler'
32
30
  end
metadata CHANGED
@@ -1,71 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: telegraf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Graichen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-16 00:00:00.000000000 Z
11
+ date: 2020-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: influxdb
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.15
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.15
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.15'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.15'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '12.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '12.0'
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '3.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '3.0'
40
+ version: '0'
69
41
  description: Metric Reporter to local telegraf agent
70
42
  email:
71
43
  - jgraichen@altimos.de
@@ -73,21 +45,36 @@ executables: []
73
45
  extensions: []
74
46
  extra_rdoc_files: []
75
47
  files:
48
+ - ".editorconfig"
76
49
  - ".gitignore"
77
50
  - ".rspec"
78
51
  - ".rubocop.yml"
79
52
  - ".travis.yml"
53
+ - Appraisals
54
+ - CHANGELOG.md
80
55
  - Gemfile
81
56
  - LICENSE
82
57
  - README.md
83
58
  - Rakefile
84
59
  - bin/console
85
60
  - bin/setup
61
+ - gemfiles/rack_2.0.gemfile
62
+ - gemfiles/rack_2.1.gemfile
63
+ - gemfiles/rack_2.2.gemfile
64
+ - gemfiles/rails_5.0.gemfile
65
+ - gemfiles/rails_5.1.gemfile
66
+ - gemfiles/rails_5.2.gemfile
67
+ - gemfiles/rails_6.0.gemfile
86
68
  - lib/telegraf.rb
69
+ - lib/telegraf/active_job.rb
87
70
  - lib/telegraf/agent.rb
71
+ - lib/telegraf/rack.rb
72
+ - lib/telegraf/rails.rb
73
+ - lib/telegraf/railtie.rb
74
+ - lib/telegraf/sidekiq.rb
88
75
  - lib/telegraf/version.rb
89
76
  - telegraf.gemspec
90
- homepage: https://github.com/jgraichen/ruby-telegraf
77
+ homepage: https://github.com/jgraichen/telegraf-ruby
91
78
  licenses:
92
79
  - LGPLv3
93
80
  metadata: {}
@@ -106,8 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
93
  - !ruby/object:Gem::Version
107
94
  version: '0'
108
95
  requirements: []
109
- rubyforge_project:
110
- rubygems_version: 2.6.12
96
+ rubygems_version: 3.0.8
111
97
  signing_key:
112
98
  specification_version: 4
113
99
  summary: Metric Reporter to local telegraf agent