Skip to content

Commit ea47872

Browse files
supports collecting metrics and logs (#7)
supports collecting metrics and logs
1 parent a3fc0c7 commit ea47872

29 files changed

+1396
-44
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@ Changes by Version
22
==================
33
Release Notes.
44

5+
0.2.0
6+
------------------
7+
#### Features
8+
- Supports collecting metrics and logs.
9+
10+
#### Plugins
11+
12+
#### Documentation
13+
514
0.1.0
615
------------------
716
#### Features

Gemfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ source 'https://rubygems.org'
1717

1818
gemspec name: 'skywalking'
1919

20-
ruby ">= 3.0.0"
20+
ruby ">= 3.0.0"
21+
22+
# Optional dependencies for enhanced performance
23+
# Uncomment the following line to enable FFI for better system call performance
24+
# gem 'ffi', '~> 1.17'
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Ruby Agent Meter and Log Reporter
2+
3+
The meter reporter feature enables collection and reporting of runtime metrics to the SkyWalking OAP backend.
4+
5+
### Runtime Metrics (Enabled by Default)
6+
7+
The agent automatically collects Ruby runtime metrics when `meter_reporter_active` is enabled (default: true).
8+
9+
#### Collected Runtime Metrics
10+
11+
**CPU Metrics:**
12+
13+
- `instance_ruby_cpu_usage_percent` - Ruby process CPU usage percentage
14+
15+
**Memory Metrics:**
16+
17+
- `instance_ruby_memory_rss_mb` - Ruby process RSS memory usage in MB
18+
- `instance_ruby_memory_usage_percent` - Ruby process memory usage percentage
19+
20+
**Garbage Collection Metrics:**
21+
22+
- `instance_ruby_gc_count_total` - Total GC execution count
23+
- `instance_ruby_gc_minor_count_total` - Minor GC count (if available)
24+
- `instance_ruby_gc_major_count_total` - Major GC count (if available)
25+
- `instance_ruby_gc_time_total` - Total GC time in milliseconds (cumulative)
26+
- `instance_ruby_heap_usage_percent` - Heap memory usage percentage
27+
- `instance_ruby_heap_live_slots_count` - Number of live heap slots
28+
- `instance_ruby_heap_available_slots_count` - Number of available heap slots
29+
30+
**Thread Metrics:**
31+
32+
- `instance_ruby_thread_count_active` - Number of active threads (all alive threads)
33+
- `instance_ruby_thread_count_running` - Number of threads in running state
34+
35+
### Log Integration
36+
37+
When log reporter is enabled, the agent automatically:
38+
39+
- **Intercepts Ruby Standard Logger**: Automatically patches the `Logger` class to collect logs
40+
- **Integrates Trace Context**: Adds trace ID, segment ID, and span ID to log messages when available
41+
42+
#### Supported Logger
43+
44+
Currently, the agent supports:
45+
46+
- **Ruby Standard Logger** (`Logger` class) - Automatically intercepted and collected
47+
48+
#### Log Configuration Options
49+
50+
```ruby
51+
# Configure log reporter level (default: Logger::INFO)
52+
config[:log_reporter_level] = Logger::INFO
53+
54+
# Configure log report period in seconds (default: 5)
55+
config[:log_report_period] = 5
56+
57+
# Configure maximum log queue size (default: 1000)
58+
config[:max_log_queue_size] = 1000
59+
```

docs/en/setup/quick-start.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ gem build skywalking.gemspec
3333

3434
If successful, the following will be displayed:
3535

36-
```ruby
36+
```shell
3737
Successfully built RubyGem
3838
Name: skywalking
3939
Version: <version>
@@ -84,27 +84,39 @@ The following is an example of configuration at start:
8484
Skywalking.start(
8585
service_name: 'sw-srv',
8686
instance_name: 'sw-inst',
87-
collector_backend_services: 'oap:11800'
87+
collector_backend_services: 'oap:11800',
88+
meter_reporter_active: true,
89+
log_reporter_active: true,
90+
meter_report_period: 30,
91+
log_report_period: 10
8892
)
8993
~~~
9094

9195
The following is an example of a configuration file:
96+
9297
~~~yaml
9398
common: &defaults
9499
service_name: Ruby-Agent-Common
95100
log_level: debug
101+
meter_reporter_active: true
102+
log_reporter_active: true
103+
meter_report_period: 20
104+
log_report_period: 5
96105

97106
development:
98107
<<: *defaults
99108
service_name: Ruby-Agent-Development
109+
log_reporter_level: 0 # DEBUG
100110

101111
test:
102112
<<: *defaults
103113
service_name: Ruby-Agent-Test
114+
log_reporter_level: 1 # INFO
104115

105116
production:
106117
<<: *defaults
107118
service_name: Ruby-Agent-Production
119+
log_reporter_level: 2 # WARN
108120
~~~
109121

110122
The following lists all the configuration options:
@@ -127,3 +139,10 @@ The following lists all the configuration options:
127139
| collector_heartbeat_period | SW_AGENT_COLLECTOR_HEARTBEAT_PERIOD | 30 | he agent will send heartbeat to OAP every `collector_heartbeat_period` seconds. |
128140
| properties_report_period_factor | SW_AGENT_PROPERTIES_REPORT_PERIOD_FACTOR | 10 | The agent will report service instance properties every `collector_heartbeat_period * properties_report_period_factor` seconds. |
129141
| max_queue_size | SW_AGENT_MAX_QUEUE_SIZE | 10000 | The maximum queue size for reporting data. |
142+
| meter_reporter_active | SW_AGENT_METER_REPORTER_ACTIVE | true | Enable/disable meter reporter for runtime metrics collection. |
143+
| meter_report_period | SW_AGENT_METER_REPORT_PERIOD | 60 | Meter report period in seconds. |
144+
| max_meter_queue_size | SW_AGENT_MAX_METER_QUEUE_SIZE | 1000 | Maximum meter queue size for buffering metrics data. |
145+
| log_reporter_active | SW_AGENT_LOG_REPORTER_ACTIVE | true | Enable/disable log reporter for log collection. |
146+
| log_reporter_level | SW_AGENT_LOG_REPORTER_LEVEL | 1 (INFO) | Minimum log level to report (Logger::DEBUG=0, INFO=1, WARN=2, ERROR=3, FATAL=4). |
147+
| log_report_period | SW_AGENT_LOG_REPORT_PERIOD | 5 | Log report period in seconds. |
148+
| max_log_queue_size | SW_AGENT_MAX_LOG_QUEUE_SIZE | 1000 | Maximum log queue size for buffering log data. |

docs/menu.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ catalog:
2323
catalog:
2424
- name: Supported Plugins
2525
path: /en/agent/plugins
26+
- name: Meter and Log Report
27+
path: /en/agent/meter-and-log-report
2628
- name: Development and Contribution
2729
catalog:
2830
- name: How to Release

lib/skywalking/agent.rb

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
require_relative 'environment'
1818
require_relative 'plugins_manager'
1919
require_relative 'reporter/report'
20+
require_relative 'reporter/log_buffer_trigger'
2021
require_relative 'tracing/span_context'
2122
require_relative 'tracing/carrier_item'
2223
require_relative 'tracing/segment'
@@ -62,13 +63,21 @@ def started?
6263
end
6364

6465
attr_reader :logger, :agent_config
66+
67+
# Get the singleton instance
68+
# @return [Agent, nil] the agent instance or nil if not started
69+
def instance
70+
@agent
71+
end
6572
end
6673

67-
attr_reader :plugins, :reporter
74+
attr_reader :plugins, :reporter, :log_buffer, :config
6875

6976
def initialize(config)
77+
@config = config
7078
@plugins = Plugins::PluginsManager.new(config)
7179
@reporter = Reporter::Report.new(config)
80+
@log_buffer = Reporter::LogBufferTrigger.new(config)
7281

7382
add_shutdown_hook
7483
end
@@ -80,6 +89,9 @@ def environment
8089
def start!
8190
@plugins.init_plugins
8291
@reporter.init_reporter
92+
# Start log reporting thread
93+
start_log_reporting_thread if @config[:log_reporter_active]
94+
8395
self
8496
end
8597

@@ -94,5 +106,46 @@ def add_shutdown_hook
94106
shutdown
95107
end
96108
end
109+
110+
# Check if log reporter is active
111+
# @return [Boolean] true if log reporter is active
112+
def log_reporter_active?
113+
@config[:log_reporter_active]
114+
end
115+
116+
private
117+
118+
# Start the log reporting thread
119+
def start_log_reporting_thread
120+
Thread.new do
121+
loop do
122+
break unless log_reporter_active?
123+
124+
process_log_queue
125+
sleep @config[:log_report_period]
126+
end
127+
end
128+
end
129+
130+
# Process the log queue and send data to the server
131+
def process_log_queue
132+
log_count = 0
133+
enumerator = Enumerator.new do |yielder|
134+
while (log_data = log_buffer.stream_data)
135+
log_data.each do |data|
136+
log_count += 1
137+
yielder << data
138+
end
139+
end
140+
end
141+
142+
enumerator.each_slice(10) do |batch|
143+
begin
144+
reporter.report_log(batch)
145+
rescue => e
146+
Agent.logger.warn "Failed to report log data: #{e.message}"
147+
end
148+
end
149+
end
97150
end
98151
end

lib/skywalking/configuration.rb

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,46 @@ class Configuration
100100
default: 10000,
101101
desc: 'The maximum queue size for reporting data'
102102
},
103+
:meter_reporter_active => {
104+
type: :bool,
105+
default: true,
106+
desc: 'Enable meter reporter'
107+
},
108+
:runtime_meter_reporter_active => {
109+
type: :bool,
110+
default: true,
111+
desc: 'Enable Ruby runtime meter reporter'
112+
},
113+
:meter_report_period => {
114+
type: :int,
115+
default: 60,
116+
desc: 'Meter report period in seconds'
117+
},
118+
:max_meter_queue_size => {
119+
type: :int,
120+
default: 1000,
121+
desc: 'Maximum meter queue size'
122+
},
123+
:log_reporter_active => {
124+
type: :bool,
125+
default: true,
126+
desc: 'Enable log reporter'
127+
},
128+
:log_reporter_level => {
129+
type: :int,
130+
default: Logger::INFO,
131+
desc: 'Minimum log level to report (Logger::DEBUG, Logger::INFO, Logger::WARN, Logger::ERROR, Logger::FATAL)'
132+
},
133+
:log_report_period => {
134+
type: :int,
135+
default: 5,
136+
desc: 'Log report period in seconds'
137+
},
138+
:max_log_queue_size => {
139+
type: :int,
140+
default: 1000,
141+
desc: 'Maximum log queue size'
142+
}
103143
}.freeze
104144

105145
# @api private
@@ -173,18 +213,18 @@ def override_config_by_env
173213
next if env_value.nil?
174214

175215
type = env_schema[:type]
176-
case type
177-
when :string
178-
new_config[env_key] = env_value.to_s
179-
when :bool
180-
# rubocop:disable Performance/CollectionLiteralInLoop
181-
new_config[env_key] = !%w[0 false].include?(env_value.strip.downcase)
182-
# rubocop:enable Performance/CollectionLiteralInLoop
183-
when :int
184-
new_config[env_key] = env_value.to_s
185-
else
186-
env_value
187-
end
216+
new_config[env_key] = case type
217+
when :string
218+
env_value.to_s
219+
when :bool
220+
# rubocop:disable Performance/CollectionLiteralInLoop
221+
!%w[0 false].include?(env_value.strip.downcase)
222+
# rubocop:enable Performance/CollectionLiteralInLoop
223+
when :int
224+
env_value.to_i
225+
else
226+
env_value
227+
end
188228
end
189229

190230
new_config

lib/skywalking/environment.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def app_name
3737
rescue
3838
nil
3939
end
40-
40+
4141
def env
4242
::Rails.env
4343
end
@@ -63,7 +63,7 @@ def app_name
6363
rescue
6464
"Sinatra"
6565
end
66-
66+
6767
def env
6868
ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
6969
end
@@ -81,7 +81,7 @@ def present?
8181
def app_name
8282
"Ruby"
8383
end
84-
84+
8585
def env
8686
ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
8787
end
@@ -111,7 +111,7 @@ def framework_root
111111
"."
112112
end
113113
end
114-
114+
115115
def framework_env
116116
@framework_env ||= framework_info.env
117117
end

lib/skywalking/meter.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
require_relative 'meter/base'
17+
require_relative 'meter/meter_service'
18+
require_relative 'meter/runtime/cpu_data_source'
19+
require_relative 'meter/runtime/mem_data_source'
20+
require_relative 'meter/runtime/gc_data_source'
21+
require_relative 'meter/runtime/thread_data_source'
22+
23+
module Skywalking
24+
# Main module for meter functionality
25+
module Meter
26+
# Classes are already defined through require statements above
27+
# No need to reassign them to themselves
28+
end
29+
end

0 commit comments

Comments
 (0)