fluent-plugin-jfrog-metrics 0.2.15 → 0.2.17

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
2
  SHA256:
3
- metadata.gz: e129c6f7bc3ddd71533676e19f0684500cbceb9785db59e514d3e18a6d42a856
4
- data.tar.gz: 1ae603b9e3ed77ed7d66ec8ba92eea76461b25b4b064f168d562b222c0d59234
3
+ metadata.gz: 87d664942597bf1b01b10d646cfd7688e86c9eefe43488d4357777e4b2e30abb
4
+ data.tar.gz: 1f622fe466d1c2490ccc3719b06fc1d43dd888a24f725fb10bb7d760e001870e
5
5
  SHA512:
6
- metadata.gz: 2338a45c27238e28b806916812acf7c33e64d7df4d1b8af67447e6b05ab0a7db5e58ada412dccd8ec4e95a27fe14037ec34f798cf0a4847ff3911980de2ef13a
7
- data.tar.gz: f2ac0b3afca4d3301455ba5ae565e585f6eba3fcb930a34db5b488069fa83e3411c7bdb08892268ee632a4e9772889fcb4cce45956c6bd6ee4ea9f1da7b10c09
6
+ metadata.gz: 7eebd867297ddb78732c1c72621e3a89064ec3273893fee443f32403dd3cccf4b0c3ecc8bed29230545561b2c5dc0ad0f3b09296a9302f03df8da11fe0f6a31f
7
+ data.tar.gz: fc09d5541762477d5e8405e712abf72df64ab94bf7f6af88eaa0bcd8bda671d5f89e94f28c2d67c9692a40eb40c17a4752b4afe71020219a4db35194308fa07d
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ fluent-plugin-jfrog-metrics-*.gem
3
+ fluent-plugin-jfrog-metrics.iml
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/CHANGELOG.md CHANGED
@@ -1,24 +1,22 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to this project will be documented in this file.
3
+ ## v0.2.17
4
+ - Fixed timestamp handling in NewRelic and Splunk metrics parsers for Prometheus metrics without timestamps ([JOBS-2118](https://jfrog-int.atlassian.net/browse/JOBS-2118))
5
+ - Metrics without timestamps (e.g., RTFS) now use current time instead of epoch 0, preventing silent rejection by New Relic Metric API
4
6
 
5
- ## [0.2.15] - 2026-03-24
7
+ ## v0.2.16
8
+ - Added RTFS (JFrog Artifactory Federation Service) metrics endpoint support ([JOBS-1897](https://jfrog-int.atlassian.net/browse/JOBS-1897))
9
+ - New metric_prefix `jfrog.rtfs` maps to `/rtfs/api/v1/metrics`
6
10
 
7
- ### Fixed
8
- - **JOBS-2011**: Fixed regex parsing issue that caused metrics shipping to fail when Artifactory emits metrics with nested curly braces in label values
9
- - Changed regex from greedy `/(.*){(.*)}(.*)/i` to non-greedy `/(.*?){(.*)}(.*)/i` in all three parser files:
10
- - `datadog_metrics_parser.rb`
11
- - `splunk_metrics_parser.rb`
12
- - `newrelic_metrics_parser.rb`
13
- - This fix resolves the "no implicit conversion of nil into String" error when parsing metrics like:
14
- ```
15
- db_query_large_total{action="/artifactory/api/nuget/{repoKey}/Download/{packageId}/{packageVersion}",application="Artifactory"} 1.0
16
- ```
11
+ ## v0.2.13
12
+ - Added fix to parse metrics without timestamps (JOBS-1801)
13
+ - Honour NO_PROXY environment variable for log analytics solutions (JOBS-1732)
17
14
 
18
- ### Added
19
- - Unit tests for metrics with nested curly braces to prevent regression
15
+ ## v0.2.12
16
+ - Add FluentD logger option to metrics plugins (PTRENG-6541)
17
+ - Fix wrapper for gzip stream handling (PTRENG-6489)
18
+ - Enhance HTTP request timeout handling (PTRENG-6489)
20
19
 
21
- ## [0.2.14] - 2026-01-19
22
-
23
- ### Previous Release
24
- - See previous release notes for earlier changes
20
+ ## v0.2.11
21
+ - Add support for verify_ssl flag (PTRENG-6164)
22
+ - Add http_proxy param support for API calls to vendors (PTRENG-6261)
data/Gemfile.lock ADDED
@@ -0,0 +1,81 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fluent-plugin-jfrog-metrics (0.2.13)
5
+ fluentd (>= 0.14.10, < 2)
6
+ rest-client (~> 2.1.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ansi (1.5.0)
12
+ builder (3.2.4)
13
+ concurrent-ruby (1.2.2)
14
+ cool.io (1.7.1)
15
+ domain_name (0.5.20190701)
16
+ unf (>= 0.0.5, < 1.0.0)
17
+ fluentd (1.16.1)
18
+ bundler
19
+ cool.io (>= 1.4.5, < 2.0.0)
20
+ http_parser.rb (>= 0.5.1, < 0.9.0)
21
+ msgpack (>= 1.3.1, < 2.0.0)
22
+ serverengine (>= 2.3.2, < 3.0.0)
23
+ sigdump (~> 0.2.2)
24
+ strptime (>= 0.2.4, < 1.0.0)
25
+ tzinfo (>= 1.0, < 3.0)
26
+ tzinfo-data (~> 1.0)
27
+ webrick (~> 1.4)
28
+ yajl-ruby (~> 1.0)
29
+ http-accept (1.7.0)
30
+ http-cookie (1.0.4)
31
+ domain_name (~> 0.5)
32
+ http_parser.rb (0.8.0)
33
+ mime-types (3.4.1)
34
+ mime-types-data (~> 3.2015)
35
+ mime-types-data (3.2021.1115)
36
+ minitest (5.14.4)
37
+ minitest-reporters (1.4.3)
38
+ ansi
39
+ builder
40
+ minitest (>= 5.0)
41
+ ruby-progressbar
42
+ msgpack (1.7.1)
43
+ netrc (0.11.0)
44
+ power_assert (2.0.1)
45
+ rake (12.3.3)
46
+ rest-client (2.1.0)
47
+ http-accept (>= 1.7.0, < 2.0)
48
+ http-cookie (>= 1.0.2, < 2.0)
49
+ mime-types (>= 1.16, < 4.0)
50
+ netrc (~> 0.8)
51
+ ruby-progressbar (1.11.0)
52
+ serverengine (2.3.2)
53
+ sigdump (~> 0.2.2)
54
+ sigdump (0.2.4)
55
+ strptime (0.2.5)
56
+ test-unit (3.5.0)
57
+ power_assert
58
+ tzinfo (2.0.6)
59
+ concurrent-ruby (~> 1.0)
60
+ tzinfo-data (1.2023.3)
61
+ tzinfo (>= 1.0.0)
62
+ unf (0.1.4)
63
+ unf_ext
64
+ unf_ext (0.0.8)
65
+ webrick (1.8.1)
66
+ yajl-ruby (1.4.3)
67
+
68
+ PLATFORMS
69
+ ruby
70
+
71
+ DEPENDENCIES
72
+ bundler (~> 1.14)
73
+ fluent-plugin-jfrog-metrics!
74
+ minitest
75
+ minitest-reporters (>= 0.5.0)
76
+ rake (~> 12.0)
77
+ rest-client (>= 2.1.0)
78
+ test-unit (~> 3.0)
79
+
80
+ BUNDLED WITH
81
+ 1.17.3
@@ -3,19 +3,22 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = 'fluent-plugin-jfrog-metrics'
6
- spec.version = '0.2.15'
6
+ spec.version = '0.2.17'
7
7
  spec.authors = ['MahithaB, BenHarosh']
8
8
  spec.email = ['cpe-support@jfrog.com']
9
9
 
10
- spec.summary = %q{Fluentd Plugin for converting JFrog Artifactory, Xray generated metrics (Prometheus Exposition Format) to target observability platform format (Splunk HEC, New Relic, DataDog)}
11
- spec.description = %q{Fluentd Plugin for converting JFrog Artifactory, Xray generated metrics (Prometheus Exposition Format) to target observability platform format (Splunk HEC, New Relic, DataDog)}
10
+ spec.summary = %q{Fluentd Plugin for converting JFrog Artifactory, Xray, RTFS generated metrics (Prometheus Exposition Format) to target observability platform format (Splunk HEC, New Relic, DataDog)}
11
+ spec.description = %q{Fluentd Plugin for converting JFrog Artifactory, Xray, RTFS generated metrics (Prometheus Exposition Format) to target observability platform format (Splunk HEC, New Relic, DataDog)}
12
12
 
13
13
  spec.homepage = 'https://github.com/jfrog/jfrog-fluentd-plugins/tree/main/fluent-plugin-jfrog-metrics'
14
14
  spec.license = 'Apache-2.0'
15
15
 
16
- spec.files = Dir['lib/**/*', 'README.md', 'LICENSE', 'CHANGELOG.md', 'Gemfile', 'Rakefile', '*.gemspec']
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = Dir['test/**/*', 'spec/**/*']
16
+ test_files, files = `git ls-files -z`.split("\x0").partition do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.files = files
20
+ spec.executables = files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = test_files
19
22
  spec.require_paths = ['lib']
20
23
 
21
24
  spec.add_development_dependency 'bundler', '~> 1.14'
@@ -26,6 +26,8 @@ class MetricsHelper
26
26
  "#{@jpd_url}/artifactory/api/v1/metrics"
27
27
  when 'jfrog.xray'
28
28
  "#{@jpd_url}/xray/api/v1/metrics"
29
+ when 'jfrog.rtfs'
30
+ "#{@jpd_url}/rtfs/api/v1/metrics"
29
31
  else
30
32
  "#{@jpd_url}/artifactory/api/v1/metrics"
31
33
  end
@@ -24,19 +24,20 @@ class NewRelicMetricsParser < BaseMetricsParser
24
24
  interim_data_key = pair_data.split("=", 2)[0]
25
25
  attributes[interim_data_key] = interim_data_value
26
26
  end
27
- if metric_val_and_time =~ / /
28
- metrics_hash['name'] = prefix + separator + metric_name
29
- metrics_hash['value'] =
30
- metric_val_and_time.strip.split[0] =~ /^\S*\.\S*$/ ? metric_val_and_time.strip.split[0].to_f : metric_val_and_time.strip.split[0].to_i
31
- metrics_hash['timestamp'] = metric_val_and_time.strip.split[1].to_i
32
- metrics_hash['attributes'] = attributes
33
- end
27
+ parts = metric_val_and_time.strip.split
28
+ metrics_hash['name'] = prefix + separator + metric_name
29
+ metrics_hash['value'] =
30
+ parts[0] =~ /^\S*\.\S*$/ ? parts[0].to_f : parts[0].to_i
31
+ parsed_ts = parts[1].to_i
32
+ metrics_hash['timestamp'] = parsed_ts > 0 ? parsed_ts : Time.now.to_i
33
+ metrics_hash['attributes'] = attributes
34
34
  else
35
- metrics_hash['name'], metrics_hash['value'], metrics_hash['timestamp'] = interim_data.split
35
+ metrics_hash['name'], metrics_hash['value'], raw_ts = interim_data.split
36
36
  metrics_hash['name'] = prefix + separator + metrics_hash['name']
37
37
  metrics_hash['value'] =
38
38
  metrics_hash['value'] =~ /^\S*\.\S*$/ ? metrics_hash['value'].to_f : metrics_hash['value'].to_i
39
- metrics_hash['timestamp'] = metrics_hash['timestamp'].to_i
39
+ parsed_ts = raw_ts.to_i
40
+ metrics_hash['timestamp'] = parsed_ts > 0 ? parsed_ts : Time.now.to_i
40
41
  end
41
42
  data_array << metrics_hash
42
43
  end
@@ -21,23 +21,24 @@ class SplunkMetricsParser < BaseMetricsParser
21
21
  metrics_hash = {}
22
22
  if data =~ /{/ && data =~ /}/
23
23
  metric_name, additional_dims, metric_val_and_time = data.match(/(.*?){(.*)}(.*)/i).captures
24
- if metric_val_and_time =~ / /
25
- metrics_hash['metric_name'] = prefix + separator + metric_name
26
- metrics_hash['value'] =
27
- metric_val_and_time.strip.split[0] =~ /^\S*\.\S*$/ ? metric_val_and_time.strip.split[0].to_f : metric_val_and_time.strip.split[0].to_i
28
- metrics_hash['time'] = metric_val_and_time.strip.split[1].to_i
29
- if additional_dims =~ /,/
30
- additional_dims.split(/,/).map do |interim_data|
31
- metrics_hash[interim_data.split(/=/)[0]] = interim_data.split(/=/)[1].gsub(/"/, '') if interim_data =~ /=/
32
- end
24
+ parts = metric_val_and_time.strip.split
25
+ metrics_hash['metric_name'] = prefix + separator + metric_name
26
+ metrics_hash['value'] =
27
+ parts[0] =~ /^\S*\.\S*$/ ? parts[0].to_f : parts[0].to_i
28
+ parsed_ts = parts[1].to_i
29
+ metrics_hash['time'] = parsed_ts > 0 ? parsed_ts : Time.now.to_i
30
+ if additional_dims =~ /,/
31
+ additional_dims.split(/,/).map do |interim_data|
32
+ metrics_hash[interim_data.split(/=/)[0]] = interim_data.split(/=/)[1].gsub(/"/, '') if interim_data =~ /=/
33
33
  end
34
34
  end
35
35
  else
36
- metrics_hash['metric_name'], metrics_hash['value'], metrics_hash['time'] = data.split
36
+ metrics_hash['metric_name'], metrics_hash['value'], raw_ts = data.split
37
37
  metrics_hash['metric_name'] = prefix + separator + metrics_hash['metric_name']
38
38
  metrics_hash['value'] =
39
39
  metrics_hash['value'] =~ /^\S*\.\S*$/ ? metrics_hash['value'].to_f : metrics_hash['value'].to_i
40
- metrics_hash['time'] = metrics_hash['time'].to_i
40
+ parsed_ts = raw_ts.to_i
41
+ metrics_hash['time'] = parsed_ts > 0 ? parsed_ts : Time.now.to_i
41
42
  end
42
43
  metrics_hash
43
44
  end
@@ -0,0 +1,25 @@
1
+ # HELP application_ready_time_seconds Time taken for the application to be ready to service requests
2
+ # TYPE application_ready_time_seconds gauge
3
+ application_ready_time_seconds{application="Federation",main_application_class="org.jfrog.rtfs.devenv.ArtifactoryFederationServiceApplicationStartup"} 18.218
4
+ # HELP application_started_time_seconds Time taken to start the application
5
+ # TYPE application_started_time_seconds gauge
6
+ application_started_time_seconds{application="Federation",main_application_class="org.jfrog.rtfs.devenv.ArtifactoryFederationServiceApplicationStartup"} 5.931
7
+ # HELP disk_free_bytes Usable space for path
8
+ # TYPE disk_free_bytes gauge
9
+ disk_free_bytes{application="Federation",path="/var/opt/jfrog/artifactory/."} 8.57595199488E11
10
+ # HELP disk_total_bytes Total space for path
11
+ # TYPE disk_total_bytes gauge
12
+ disk_total_bytes{application="Federation",path="/var/opt/jfrog/artifactory/."} 9.77896124416E11
13
+ # HELP executor_active_threads The approximate number of threads that are actively executing tasks
14
+ # TYPE executor_active_threads gauge
15
+ executor_active_threads{application="Federation",name="binariesTaskMetricsCollectorScheduler"} 0.0
16
+ # HELP jvm_memory_used_bytes The amount of used memory
17
+ # TYPE jvm_memory_used_bytes gauge
18
+ jvm_memory_used_bytes{application="Federation",area="heap",id="G1 Eden Space"} 1.6777216E7
19
+ jvm_memory_used_bytes{application="Federation",area="heap",id="G1 Old Gen"} 7.4136896E7
20
+ # HELP process_cpu_usage The recent cpu usage for the JVM process
21
+ # TYPE process_cpu_usage gauge
22
+ process_cpu_usage{application="Federation"} 0.003
23
+ # HELP simple_metric_no_labels A metric without labels or timestamp
24
+ # TYPE simple_metric_no_labels gauge
25
+ simple_metric_no_labels 42
@@ -28,6 +28,7 @@ RSpec.describe DatadogMetricsParser do
28
28
 
29
29
  hash_data_array = parser.format_data(cleaned_data, 'jfrog.artifactory', '.')
30
30
  expect(hash_data_array.size).to be 1
31
+ expect(hash_data_array[0]['series'].size).to be > 1
31
32
 
32
33
  serialized_data = parser.serialize_data(hash_data_array)
33
34
  expect(serialized_data.size).to be 1
@@ -47,16 +48,17 @@ RSpec.describe DatadogMetricsParser do
47
48
 
48
49
  hash_data_array = parser.format_data(cleaned_data, 'jfrog.xray', '.')
49
50
  expect(hash_data_array.size).to be 1
51
+ expect(hash_data_array[0]['series'].size).to be > 1
50
52
 
51
53
  serialized_data = parser.serialize_data(hash_data_array)
52
54
  expect(serialized_data.size).to be 1
53
55
  end
54
56
 
55
- it 'should correctly parse metrics with nested curly braces in labels (JOBS-2011)' do
56
- platform_metrics = File.read('./spec/fixtures/files/sample_metrics_with_nested_braces.txt')
57
+ it 'should parse RTFS metrics with jfrog.rtfs prefix and verify all metric names are prefixed' do
58
+ platform_metrics = File.read('./spec/fixtures/files/sample_artifactory_metrics.txt')
57
59
  expect(platform_metrics.size).to be > 1
58
60
 
59
- parser = DatadogMetricsParser.new('jfrog.artifactory', '', 'jfrog.artifactory.metrics')
61
+ parser = DatadogMetricsParser.new('jfrog.rtfs', '', 'jfrog.metrics.rtfs')
60
62
 
61
63
  normalized_data = parser.normalise_data(platform_metrics)
62
64
  expect(normalized_data.size).to be > 1
@@ -64,44 +66,35 @@ RSpec.describe DatadogMetricsParser do
64
66
  cleaned_data = parser.clean_data(normalized_data)
65
67
  expect(cleaned_data.size).to be > 1
66
68
 
67
- hash_data_array = parser.format_data(cleaned_data, 'jfrog.artifactory', '.')
69
+ hash_data_array = parser.format_data(cleaned_data, 'jfrog.rtfs', '.')
68
70
  expect(hash_data_array.size).to be 1
71
+ expect(hash_data_array[0]['series'].size).to be > 1
69
72
 
70
- series_array = hash_data_array[0]['series']
71
- expect(series_array.size).to be > 1
72
-
73
- series_array.each do |metric|
74
- expect(metric['metric']).to start_with('jfrog.artifactory.')
75
- expect(metric['metric']).not_to include('{')
73
+ hash_data_array[0]['series'].each do |metric|
74
+ expect(metric['metric']).to start_with('jfrog.rtfs.')
76
75
  expect(metric['points']).not_to be_nil
77
76
  expect(metric['points'].size).to be >= 1
77
+ expect(metric['points'][0]['value']).to be_a(Numeric)
78
78
  end
79
- end
80
-
81
- it 'should parse single metric with nested braces correctly' do
82
- metric_line = 'db_query_large_total{action="/artifactory/api/nuget/{repoKey}/Download/{packageId}/{packageVersion}",application="Artifactory",group="download",package="nuget"} 2.0 1711100784000'
83
79
 
84
- parser = DatadogMetricsParser.new('jfrog.artifactory', '', 'jfrog.artifactory.metrics')
85
- result = parser.format_data([metric_line], 'jfrog.artifactory', '.')
86
-
87
- expect(result.size).to eq(1)
88
- series = result[0]['series']
89
- expect(series.size).to eq(1)
90
- expect(series[0]['metric']).to eq('jfrog.artifactory.db_query_large_total')
91
- expect(series[0]['points'][0]['value']).to eq(2.0)
92
- expect(series[0]['tags']).to include('action:/artifactory/api/nuget/{repoKey}/Download/{packageId}/{packageVersion}')
93
- expect(series[0]['tags']).to include('application:Artifactory')
80
+ serialized_data = parser.serialize_data(hash_data_array)
81
+ expect(serialized_data.size).to be 1
94
82
  end
95
83
 
96
- it 'should not crash with nil values when parsing nested braces (regression test)' do
97
- metric_with_complex_braces = 'db_query_large_total{action="/artifactory/api/artifactproperties{name:(/[^/]+?)?}",application="Artifactory",group="",package=""} 1.0 1711100784000'
84
+ it 'should parse a single RTFS metric line correctly' do
85
+ single_metric = "sys_memory_used_bytes 3836522496 1645738619452"
98
86
 
99
- parser = DatadogMetricsParser.new('jfrog.artifactory', '', 'jfrog.artifactory.metrics')
87
+ parser = DatadogMetricsParser.new('jfrog.rtfs', '', 'jfrog.metrics.rtfs')
88
+
89
+ hash_data_array = parser.format_data([single_metric], 'jfrog.rtfs', '.')
90
+ expect(hash_data_array.size).to be 1
91
+ expect(hash_data_array[0]['series'].size).to be 1
100
92
 
101
- expect {
102
- result = parser.format_data([metric_with_complex_braces], 'jfrog.artifactory', '.')
103
- expect(result[0]['series'][0]['metric']).to eq('jfrog.artifactory.db_query_large_total')
104
- }.not_to raise_error
93
+ metric = hash_data_array[0]['series'][0]
94
+ expect(metric['metric']).to eq('jfrog.rtfs.sys_memory_used_bytes')
95
+ expect(metric['points'][0]['value']).to eq(3836522496)
96
+ expect(metric['points'][0]['timestamp']).to eq(1645738619)
97
+ expect(metric['type']).to eq(3)
105
98
  end
106
99
  end
107
100
  end
@@ -52,11 +52,11 @@ RSpec.describe NewRelicMetricsParser do
52
52
  expect(serialized_data.size).to be 1
53
53
  end
54
54
 
55
- it 'should correctly parse metrics with nested curly braces in labels (JOBS-2011)' do
56
- platform_metrics = File.read('./spec/fixtures/files/sample_metrics_with_nested_braces.txt')
55
+ it 'should parse RTFS metrics with jfrog.rtfs prefix and verify all metric names are prefixed' do
56
+ platform_metrics = File.read('./spec/fixtures/files/sample_artifactory_metrics.txt')
57
57
  expect(platform_metrics.size).to be > 1
58
58
 
59
- parser = NewRelicMetricsParser.new('jfrog.artifactory', '', 'jfrog.artifactory.metrics')
59
+ parser = NewRelicMetricsParser.new('jfrog.rtfs', '', 'jfrog.metrics.rtfs')
60
60
 
61
61
  normalized_data = parser.normalise_data(platform_metrics)
62
62
  expect(normalized_data.size).to be > 1
@@ -64,32 +64,40 @@ RSpec.describe NewRelicMetricsParser do
64
64
  cleaned_data = parser.clean_data(normalized_data)
65
65
  expect(cleaned_data.size).to be > 1
66
66
 
67
- hash_data_array = parser.format_data(cleaned_data, 'jfrog.artifactory', '.')
67
+ hash_data_array = parser.format_data(cleaned_data, 'jfrog.rtfs', '.')
68
68
  expect(hash_data_array.size).to be 1
69
69
 
70
- metrics_array = hash_data_array[0]['metrics']
71
- expect(metrics_array.size).to be > 1
72
-
73
- metrics_array.each do |metric|
74
- expect(metric['name']).to start_with('jfrog.artifactory.')
75
- expect(metric['name']).not_to include('{')
76
- expect(metric['value']).not_to be_nil
70
+ hash_data_array[0]['metrics'].each do |metric|
71
+ expect(metric['name']).to start_with('jfrog.rtfs.')
72
+ expect(metric['value']).to be_a(Numeric)
77
73
  end
74
+
75
+ serialized_data = parser.serialize_data(hash_data_array)
76
+ expect(serialized_data.size).to be 1
78
77
  end
79
78
 
80
- it 'should parse single metric with nested braces correctly' do
81
- metric_line = 'db_query_large_total{action="/artifactory/api/nuget/{repoKey}/Download/{packageId}/{packageVersion}",application="Artifactory",group="download",package="nuget"} 2.0 1711100784000'
79
+ it 'should assign current timestamp to RTFS metrics that lack timestamps' do
80
+ platform_metrics = File.read('./spec/fixtures/files/sample_rtfs_metrics.txt')
81
+ expect(platform_metrics.size).to be > 1
82
82
 
83
- parser = NewRelicMetricsParser.new('jfrog.artifactory', '', 'jfrog.artifactory.metrics')
84
- result = parser.format_data([metric_line], 'jfrog.artifactory', '.')
85
-
86
- expect(result.size).to eq(1)
87
- metrics = result[0]['metrics']
88
- expect(metrics.size).to eq(1)
89
- expect(metrics[0]['name']).to eq('jfrog.artifactory.db_query_large_total')
90
- expect(metrics[0]['value']).to eq(2.0)
91
- expect(metrics[0]['attributes']['action']).to eq('/artifactory/api/nuget/{repoKey}/Download/{packageId}/{packageVersion}')
92
- expect(metrics[0]['attributes']['application']).to eq('Artifactory')
83
+ parser = NewRelicMetricsParser.new('jfrog.rtfs', '', 'jfrog.metrics.rtfs')
84
+
85
+ normalized_data = parser.normalise_data(platform_metrics)
86
+ cleaned_data = parser.clean_data(normalized_data)
87
+ hash_data_array = parser.format_data(cleaned_data, 'jfrog.rtfs', '.')
88
+
89
+ expect(hash_data_array.size).to be 1
90
+ metrics = hash_data_array[0]['metrics']
91
+ expect(metrics.size).to be > 1
92
+
93
+ now = Time.now.to_i
94
+ metrics.each do |metric|
95
+ expect(metric['name']).to start_with('jfrog.rtfs.')
96
+ expect(metric['value']).to be_a(Numeric)
97
+ expect(metric['timestamp']).to be_a(Integer)
98
+ expect(metric['timestamp']).to be > 0
99
+ expect(metric['timestamp']).to be_within(5).of(now)
100
+ end
93
101
  end
94
102
  end
95
103
  end
@@ -52,11 +52,11 @@ RSpec.describe SplunkMetricsParser do
52
52
  expect(serialized_data.size).to be > 1
53
53
  end
54
54
 
55
- it 'should correctly parse metrics with nested curly braces in labels (JOBS-2011)' do
56
- platform_metrics = File.read('./spec/fixtures/files/sample_metrics_with_nested_braces.txt')
55
+ it 'should parse RTFS metrics with jfrog.rtfs prefix and verify all metric names are prefixed' do
56
+ platform_metrics = File.read('./spec/fixtures/files/sample_artifactory_metrics.txt')
57
57
  expect(platform_metrics.size).to be > 1
58
58
 
59
- parser = SplunkMetricsParser.new('jfrog.artifactory', '', 'jfrog.artifactory.metrics')
59
+ parser = SplunkMetricsParser.new('jfrog.rtfs', '', 'jfrog.metrics.rtfs')
60
60
 
61
61
  normalized_data = parser.normalise_data(platform_metrics)
62
62
  expect(normalized_data.size).to be > 1
@@ -64,26 +64,38 @@ RSpec.describe SplunkMetricsParser do
64
64
  cleaned_data = parser.clean_data(normalized_data)
65
65
  expect(cleaned_data.size).to be > 1
66
66
 
67
- hash_data_array = parser.format_data(cleaned_data, 'jfrog.artifactory', '.')
67
+ hash_data_array = parser.format_data(cleaned_data, 'jfrog.rtfs', '.')
68
68
  expect(hash_data_array.size).to be > 1
69
69
 
70
- hash_data_array.each do |metric_hash|
71
- expect(metric_hash['metric_name']).to start_with('jfrog.artifactory.')
72
- expect(metric_hash['metric_name']).not_to include('{')
73
- expect(metric_hash['value']).not_to be_nil
70
+ hash_data_array.each do |metric|
71
+ expect(metric['metric_name']).to start_with('jfrog.rtfs.')
72
+ expect(metric['value']).to be_a(Numeric)
74
73
  end
74
+
75
+ serialized_data = parser.serialize_data(hash_data_array)
76
+ expect(serialized_data.size).to be > 1
75
77
  end
76
78
 
77
- it 'should parse single metric with nested braces correctly' do
78
- metric_line = 'db_query_large_total{action="/artifactory/api/nuget/{repoKey}/Download/{packageId}/{packageVersion}",application="Artifactory",group="download",package="nuget"} 2.0 1711100784000'
79
+ it 'should assign current timestamp to RTFS metrics that lack timestamps' do
80
+ platform_metrics = File.read('./spec/fixtures/files/sample_rtfs_metrics.txt')
81
+ expect(platform_metrics.size).to be > 1
82
+
83
+ parser = SplunkMetricsParser.new('jfrog.rtfs', '', 'jfrog.metrics.rtfs')
79
84
 
80
- parser = SplunkMetricsParser.new('jfrog.artifactory', '', 'jfrog.artifactory.metrics')
81
- result = parser.generate_hash_from_data(metric_line, 'jfrog.artifactory', '.')
85
+ normalized_data = parser.normalise_data(platform_metrics)
86
+ cleaned_data = parser.clean_data(normalized_data)
87
+ hash_data_array = parser.format_data(cleaned_data, 'jfrog.rtfs', '.')
82
88
 
83
- expect(result['metric_name']).to eq('jfrog.artifactory.db_query_large_total')
84
- expect(result['value']).to eq(2.0)
85
- expect(result['action']).to eq('/artifactory/api/nuget/{repoKey}/Download/{packageId}/{packageVersion}')
86
- expect(result['application']).to eq('Artifactory')
89
+ expect(hash_data_array.size).to be > 1
90
+
91
+ now = Time.now.to_i
92
+ hash_data_array.each do |metric|
93
+ expect(metric['metric_name']).to start_with('jfrog.rtfs.')
94
+ expect(metric['value']).to be_a(Numeric)
95
+ expect(metric['time']).to be_a(Integer)
96
+ expect(metric['time']).to be > 0
97
+ expect(metric['time']).to be_within(5).of(now)
98
+ end
87
99
  end
88
100
  end
89
101
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-jfrog-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.15
4
+ version: 0.2.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - MahithaB, BenHarosh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-24 00:00:00.000000000 Z
11
+ date: 2026-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -100,17 +100,20 @@ dependencies:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
102
  version: 2.1.0
103
- description: Fluentd Plugin for converting JFrog Artifactory, Xray generated metrics
104
- (Prometheus Exposition Format) to target observability platform format (Splunk HEC,
105
- New Relic, DataDog)
103
+ description: Fluentd Plugin for converting JFrog Artifactory, Xray, RTFS generated
104
+ metrics (Prometheus Exposition Format) to target observability platform format (Splunk
105
+ HEC, New Relic, DataDog)
106
106
  email:
107
107
  - cpe-support@jfrog.com
108
108
  executables: []
109
109
  extensions: []
110
110
  extra_rdoc_files: []
111
111
  files:
112
+ - ".gitignore"
113
+ - ".rspec"
112
114
  - CHANGELOG.md
113
115
  - Gemfile
116
+ - Gemfile.lock
114
117
  - LICENSE
115
118
  - README.md
116
119
  - Rakefile
@@ -124,7 +127,7 @@ files:
124
127
  - lib/fluent/plugin/splunk_metrics_parser.rb
125
128
  - spec/fixtures/files/creds.rb
126
129
  - spec/fixtures/files/sample_artifactory_metrics.txt
127
- - spec/fixtures/files/sample_metrics_with_nested_braces.txt
130
+ - spec/fixtures/files/sample_rtfs_metrics.txt
128
131
  - spec/fixtures/files/sample_xray_metrics.txt
129
132
  - spec/lib/datadog_metrics_parser_spec.rb
130
133
  - spec/lib/metrics_helper_spec.rb
@@ -155,18 +158,18 @@ requirements: []
155
158
  rubygems_version: 3.0.3.1
156
159
  signing_key:
157
160
  specification_version: 4
158
- summary: Fluentd Plugin for converting JFrog Artifactory, Xray generated metrics (Prometheus
159
- Exposition Format) to target observability platform format (Splunk HEC, New Relic,
160
- DataDog)
161
+ summary: Fluentd Plugin for converting JFrog Artifactory, Xray, RTFS generated metrics
162
+ (Prometheus Exposition Format) to target observability platform format (Splunk HEC,
163
+ New Relic, DataDog)
161
164
  test_files:
162
- - test/helper.rb
163
- - test/plugin/test_in_jfrog_metrics.rb
164
- - spec/spec_helper.rb
165
+ - spec/fixtures/files/creds.rb
166
+ - spec/fixtures/files/sample_artifactory_metrics.txt
167
+ - spec/fixtures/files/sample_rtfs_metrics.txt
168
+ - spec/fixtures/files/sample_xray_metrics.txt
165
169
  - spec/lib/datadog_metrics_parser_spec.rb
166
- - spec/lib/splunk_metrics_parser_spec.rb
167
170
  - spec/lib/metrics_helper_spec.rb
168
171
  - spec/lib/newrelic_metrics_parser_spec.rb
169
- - spec/fixtures/files/sample_xray_metrics.txt
170
- - spec/fixtures/files/sample_metrics_with_nested_braces.txt
171
- - spec/fixtures/files/creds.rb
172
- - spec/fixtures/files/sample_artifactory_metrics.txt
172
+ - spec/lib/splunk_metrics_parser_spec.rb
173
+ - spec/spec_helper.rb
174
+ - test/helper.rb
175
+ - test/plugin/test_in_jfrog_metrics.rb
@@ -1,12 +0,0 @@
1
- # HELP db_query_large_total Total large queries
2
- # UPDATED db_query_large_total 1711100784000
3
- # TYPE db_query_large_total counter
4
- db_query_large_total{action="/artifactory/api/nuget/{repoKey}/Download/{packageId}/{packageVersion}",application="Artifactory",group="download",package="nuget"} 2.0 1711100784000
5
- # HELP db_query_large_total_alt Alternative large queries with different template
6
- # UPDATED db_query_large_total_alt 1711100784000
7
- # TYPE db_query_large_total_alt counter
8
- db_query_large_total{action="/artifactory/api/artifactproperties{name:(/[^/]+?)?}",application="Artifactory",group="",package=""} 1.0 1711100784000
9
- # HELP jfrt_http_connections_available_total Available HTTP Connections
10
- # UPDATED jfrt_http_connections_available_total 1711100784000
11
- # TYPE jfrt_http_connections_available_total gauge
12
- jfrt_http_connections_available_total{instance="node1",port="8081"} 50 1711100784000