rack-influxdb 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +80 -0
- data/Rakefile +10 -0
- data/lib/rack/influxdb/configuration.rb +33 -0
- data/lib/rack/influxdb/version.rb +5 -0
- data/lib/rack/influxdb.rb +63 -0
- data/spec/rack_influxdb_spec.rb +113 -0
- data/spec/spec_helper.rb +23 -0
- metadata +148 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 692f56fbc15ce9112783e0a51f3a323e32bcb1063db207d38684d66ef11f0c45
|
4
|
+
data.tar.gz: b6d827637d9b7162a69b04682846ffbb372bce98af6b2fa547d6d2a0dd967864
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 12047f80e2e445e38b03304590ab8b77d197d6ab6061f3e68bef009dca49e40aad006cf2eac593ec33012f9af2dd3054fda4c9ab84eedc1fc9cb4ef98b33d02b
|
7
|
+
data.tar.gz: 31cdc1e24c9e4931e545d93139a7fa4709fbc03597f3a6891f60bca98cbd695b2422fab94779af62f4f5716bf636c26891a734169fd31af69654cc3fd6b23145
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Chimpy
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# rack-influxdb
|
2
|
+
|
3
|
+
[](https://github.com/heychimpy/rack-influxdb/actions/workflows/test.yml)
|
4
|
+
|
5
|
+
This gem provides a Rack middleware for [InfluxDB](https://github.com/influxdata/influxdb).
|
6
|
+
|
7
|
+
- [Installation](#installation)
|
8
|
+
- [Usage](#usage)
|
9
|
+
- [Configuration](#configuration)
|
10
|
+
- [Basic usage](#basic-usage)
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'rack-influxdb'
|
18
|
+
```
|
19
|
+
|
20
|
+
Then run:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
bundle
|
24
|
+
```
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
### Configuration
|
29
|
+
The Rack::InfluxDB gem can be easily configured
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
Rack::InfluxDB.configure do |config|
|
33
|
+
# The name of your measurement
|
34
|
+
config.name = "http_requests"
|
35
|
+
|
36
|
+
# Custom tags
|
37
|
+
config.tags = { app: "my-awesome-api", env: "production" }
|
38
|
+
|
39
|
+
# The URL of your InfluxDB instance
|
40
|
+
config.url = "https://test.influxdb.example.com"
|
41
|
+
|
42
|
+
# The API token provided by InfluxDB
|
43
|
+
config.token = "topsecret"
|
44
|
+
|
45
|
+
# A lambda that returns a hash containing the fields to write.
|
46
|
+
# E.g. to just track the HTTP status:
|
47
|
+
config.fields = lambda { |env, response| return { status: response[0] } }
|
48
|
+
|
49
|
+
# Handle errors individually
|
50
|
+
config.handle_errors = lambda { |err| report_error(err) }
|
51
|
+
|
52
|
+
# Options like Org, Bucket and Precision
|
53
|
+
config.options = {
|
54
|
+
org: 'my-org',
|
55
|
+
bucket: 'my-bucket',
|
56
|
+
precision: InfluxDB2::WritePrecision::MILLISECOND
|
57
|
+
}
|
58
|
+
|
59
|
+
# Write options - it's highly recommended to use batching and not
|
60
|
+
# synchronous writing.
|
61
|
+
config.write_options = {
|
62
|
+
write_type: InfluxDB2::WriteType::BATCHING,
|
63
|
+
batch_size: 1_000
|
64
|
+
}
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
### Basic usage
|
69
|
+
All you have to do is to include the middleware in your Rack stack.
|
70
|
+
|
71
|
+
In Rails:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
# config/application.rb
|
75
|
+
|
76
|
+
class Application < Rails::Application
|
77
|
+
...
|
78
|
+
config.middleware.use Rack::InfluxDB
|
79
|
+
end
|
80
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Rack
|
2
|
+
class InfluxDB
|
3
|
+
class Configuration
|
4
|
+
attr_accessor :name, :tags, :url, :token, :options, :write_options,
|
5
|
+
:fields, :handle_error
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
set_defaults
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def set_defaults
|
14
|
+
@name = 'http_requests'
|
15
|
+
@tags = {}
|
16
|
+
@url = ''
|
17
|
+
@token = ''
|
18
|
+
@fields = lambda { |env, response| return {} }
|
19
|
+
@handle_error = lambda { |err| return }
|
20
|
+
@options = {
|
21
|
+
org: '',
|
22
|
+
bucket: '',
|
23
|
+
precision: InfluxDB2::WritePrecision::MILLISECOND
|
24
|
+
}
|
25
|
+
|
26
|
+
@write_options = InfluxDB2::WriteOptions.new(
|
27
|
+
write_type: InfluxDB2::WriteType::BATCHING,
|
28
|
+
batch_size: 100,
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'influxdb-client'
|
2
|
+
require 'rack/influxdb/configuration'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class InfluxDB
|
6
|
+
class << self
|
7
|
+
attr_reader :configuration
|
8
|
+
|
9
|
+
def configuration
|
10
|
+
@configuration ||= Rack::InfluxDB::Configuration.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def configure
|
14
|
+
yield(configuration)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(app)
|
19
|
+
@app = app
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
@app.call(env).tap { |response| write_request(env, response) }
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def write_request(env, response)
|
29
|
+
# The presence or absence of a token implicitly determines whether it
|
30
|
+
# should be executed at all. This allows this gem to run in each
|
31
|
+
# environment.
|
32
|
+
return if config.token.to_s.empty?
|
33
|
+
|
34
|
+
# Run the write logic inside a thread so we don't slow down
|
35
|
+
# main request.
|
36
|
+
Thread.new do
|
37
|
+
begin
|
38
|
+
InfluxDB2::Client.use(config.url, config.token, **config.options) do |c|
|
39
|
+
write_api = c.create_write_api(write_options: config.write_options)
|
40
|
+
write_api.write(data: point(env, response))
|
41
|
+
end
|
42
|
+
rescue => e
|
43
|
+
config.handle_error.call(e)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
rescue => e
|
47
|
+
# Let the app decide what needs to be done when an error occurs.
|
48
|
+
config.handle_error.call(e)
|
49
|
+
end
|
50
|
+
|
51
|
+
def point(env, response)
|
52
|
+
{
|
53
|
+
name: config.name,
|
54
|
+
tags: config.tags,
|
55
|
+
fields: config.fields.call(env, response)
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def config
|
60
|
+
Rack::InfluxDB.configuration
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Rack::InfluxDB do
|
4
|
+
describe '.configuration' do
|
5
|
+
it 'returns a new instance of Rack::InfluxDB::Configuration' do
|
6
|
+
expect(described_class.configuration)
|
7
|
+
.to be_a(Rack::InfluxDB::Configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'memoizes the configuration' do
|
11
|
+
conf = described_class.configuration
|
12
|
+
|
13
|
+
expect(described_class.configuration).to eq(conf)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.configure' do
|
18
|
+
it 'passes the configuration object to block' do
|
19
|
+
conf = described_class.configuration
|
20
|
+
|
21
|
+
expect { |block| described_class.configure(&block) }.to \
|
22
|
+
yield_with_args(conf)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'saves new configuration values' do
|
26
|
+
described_class.configure do |config|
|
27
|
+
config.name = 'test_name'
|
28
|
+
end
|
29
|
+
|
30
|
+
expect(described_class.configuration.name).to eq('test_name')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#call' do
|
35
|
+
before do
|
36
|
+
allow(Thread).to receive(:new).and_yield
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns the initial status code' do
|
40
|
+
get '/'
|
41
|
+
|
42
|
+
expect(last_response.status).to eq(200)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns the initial body' do
|
46
|
+
get '/'
|
47
|
+
|
48
|
+
expect(last_response.body).to eq('Hello World')
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when no config token is given' do
|
52
|
+
it 'does not call InfluxDB2::Client.use' do
|
53
|
+
expect(InfluxDB2::Client).not_to receive(:use)
|
54
|
+
|
55
|
+
get '/'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when config token is given' do
|
60
|
+
before do
|
61
|
+
allow(InfluxDB2::Client).to receive(:use)
|
62
|
+
|
63
|
+
described_class.configure do |config|
|
64
|
+
config.token = "token"
|
65
|
+
config.url = "example.com"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
let(:conf) { described_class.configuration }
|
70
|
+
|
71
|
+
it 'calls InfluxDB2::Client.use with right params' do
|
72
|
+
get '/'
|
73
|
+
|
74
|
+
expect(InfluxDB2::Client)
|
75
|
+
.to have_received(:use)
|
76
|
+
.with(conf.url, conf.token, conf.options)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when an error occurs' do
|
81
|
+
before do
|
82
|
+
allow(InfluxDB2::Client).to receive(:use).and_raise('Could not write')
|
83
|
+
|
84
|
+
described_class.configure do |config|
|
85
|
+
config.token = "token"
|
86
|
+
config.url = "example.com"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'the error is swallowed' do
|
91
|
+
expect { get '/' }.not_to raise_error
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'returns the initial status code' do
|
95
|
+
get '/'
|
96
|
+
|
97
|
+
expect(last_response.status).to eq(200)
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when custom error handling is applied' do
|
101
|
+
before do
|
102
|
+
described_class.configure do |config|
|
103
|
+
config.handle_error = ->(e) { raise e }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'it gets handled (re-raised)' do
|
108
|
+
expect { get '/' }.to raise_error('Could not write')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
require 'rack/test'
|
5
|
+
require 'rack/influxdb'
|
6
|
+
|
7
|
+
# The dummy app which includes the Rack::InfluxDB middleware.
|
8
|
+
def app
|
9
|
+
Rack::Builder.new do
|
10
|
+
# Include the InfluxDB middleware.
|
11
|
+
use Rack::InfluxDB
|
12
|
+
|
13
|
+
run lambda { |_env| [200, {}, ['Hello World']] }
|
14
|
+
end.to_app
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.include Rack::Test::Methods
|
19
|
+
|
20
|
+
config.expect_with :rspec do |conf|
|
21
|
+
conf.syntax = :expect
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-influxdb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Henning Vogt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-05-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '4'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '4'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: influxdb-client
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '3'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '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: '1.17'
|
54
|
+
- - "<"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '3.0'
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '1.17'
|
64
|
+
- - "<"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '3.0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rack-test
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '2.0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '2.0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rake
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '13.0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '13.0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rspec
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '3.13'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '3.13'
|
109
|
+
description: A rack middleware for logging requests to InfluxDB
|
110
|
+
email: tech@heychimpy.com
|
111
|
+
executables: []
|
112
|
+
extensions: []
|
113
|
+
extra_rdoc_files: []
|
114
|
+
files:
|
115
|
+
- LICENSE
|
116
|
+
- README.md
|
117
|
+
- Rakefile
|
118
|
+
- lib/rack/influxdb.rb
|
119
|
+
- lib/rack/influxdb/configuration.rb
|
120
|
+
- lib/rack/influxdb/version.rb
|
121
|
+
- spec/rack_influxdb_spec.rb
|
122
|
+
- spec/spec_helper.rb
|
123
|
+
homepage: https://github.com/heychimpy/rack-influxdb
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '2.7'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubygems_version: 3.3.5
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: Log HTTP requests to InfluxDB
|
146
|
+
test_files:
|
147
|
+
- spec/rack_influxdb_spec.rb
|
148
|
+
- spec/spec_helper.rb
|