telegraf 0.4.0 → 0.8.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: 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