Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
292fdd5
Fix Ruby 3.3+ ARM64 segfault during shutdown
phillip-haydon Jan 1, 2026
99e6a2a
Remove Ruby 5.x version constraints
phillip-haydon Jan 1, 2026
e3a0b38
Update build tooling for Ruby 3.0+ and rake-compiler-dock 1.11.1
phillip-haydon Jan 7, 2026
a3707f9
Fix flaky tests for Ruby 3.x compatibility
phillip-haydon Jan 7, 2026
144334d
Fix additional test failures for Ruby 3.x
phillip-haydon Jan 7, 2026
a4fee99
Fix Bundler version compatibility for TeamCity
phillip-haydon Jan 7, 2026
6960e91
Fix build script for Ruby 2.7 host compatibility
phillip-haydon Jan 7, 2026
c690193
Build script: Install Ruby 3.1 and dependencies if missing
phillip-haydon Jan 7, 2026
717af1a
Fix build script: proper Ruby version check without bc dependency
phillip-haydon Jan 7, 2026
fc595dc
Fix build script: avoid eval/source, use direct git clone for rbenv
phillip-haydon Jan 7, 2026
cd38a27
Install build dependencies before building Ruby
phillip-haydon Jan 7, 2026
81c366b
Bump required Ruby to 3.2 (multi_xml requires >= 3.1.2)
phillip-haydon Jan 8, 2026
748dd9d
Install debase-ruby_core_source globally in Docker containers
phillip-haydon Jan 8, 2026
b350090
Use cross native:PLATFORM to avoid host Ruby 4.0.0 compilation
phillip-haydon Jan 8, 2026
92f7153
Build native only, manually package gem to avoid host Ruby compilation
phillip-haydon Jan 8, 2026
0ed5fef
Run unit tests with Ruby 3.2 after build
phillip-haydon Jan 8, 2026
f08fd20
Fix GCC compatibility: old-style function def and clang-only flags
phillip-haydon Jan 8, 2026
8409a3f
Fix C99 old-style function definitions and Ruby warnings
phillip-haydon Jan 8, 2026
127f854
Fix Invalid attribute name error to show symbol name instead of pointer
phillip-haydon Jan 9, 2026
2eec172
Fix GCC 12+ compilation: C99 function definitions, rax.c use-after-fr…
phillip-haydon Feb 7, 2026
e86fa65
Bump version to 1.1.15.pre3
phillip-haydon Feb 9, 2026
27f3223
Update darwin build config for Ruby 3.x, add comprehensive README
phillip-haydon Feb 9, 2026
a2f706b
Add rake gem:all task to build all 7 platform gems in one command
phillip-haydon Feb 9, 2026
2353c5e
Update Gemfile.lock for Ruby 3.3.7
phillip-haydon Feb 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gemspec

gem 'irb'

# Required for Ruby 3.4+ (removed from default gems)
gem 'mutex_m'
gem 'ostruct'
gem 'csv'
113 changes: 68 additions & 45 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,98 +1,121 @@
PATH
remote: .
specs:
raygun-apm (1.1.15.pre1)
raygun-apm (1.1.15.pre3)
debase-ruby_core_source (>= 3.3.6)

GEM
remote: https://rubygems.org/
specs:
activemodel (6.1.3.2)
activesupport (= 6.1.3.2)
activesupport (6.1.3.2)
activemodel (6.1.7.10)
activesupport (= 6.1.7.10)
activesupport (6.1.7.10)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
benchmark_driver (0.15.17)
bson (4.12.1)
concurrent-ruby (1.1.8)
debase-ruby_core_source (0.10.14)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
base64 (0.3.0)
benchmark_driver (0.15.18)
bigdecimal (3.3.1)
bson (5.2.0)
cgi (0.5.1)
concurrent-ruby (1.3.6)
csv (3.3.5)
date (3.5.1)
debase-ruby_core_source (3.4.1)
domain_name (0.6.20240107)
erb (4.0.4)
cgi (>= 0.3.3)
excon (0.73.0)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
ffi (1.15.5-x64-mingw32)
http-accept (1.7.0)
http-cookie (1.0.3)
http-cookie (1.1.0)
domain_name (~> 0.5)
httparty (0.18.1)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.8.10)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
io-console (0.5.9)
irb (1.3.5)
reline (>= 0.1.5)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0225)
minitest (5.14.4)
mongo (2.14.0)
bson (>= 4.8.2, < 5.0.0)
mongoid (7.1.8)
io-console (0.8.2)
irb (1.16.0)
pp (>= 0.6.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
logger (1.7.0)
mime-types (3.7.0)
logger
mime-types-data (~> 3.2025, >= 3.2025.0507)
mime-types-data (3.2025.0924)
minitest (5.27.0)
mongo (2.22.0)
base64
bson (>= 4.14.1, < 6.0.0)
mongoid (7.1.11)
activemodel (>= 5.1, < 6.2)
mongo (>= 2.7.0, < 3.0.0)
multi_xml (0.6.0)
ruby2_keywords (~> 0.0.5)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
multipart-post (2.1.1)
mutex_m (0.3.0)
netrc (0.11.0)
rake (13.0.3)
rake-compiler (1.1.1)
ostruct (0.6.3)
pp (0.6.3)
prettyprint
prettyprint (0.2.0)
psych (5.3.1)
date
stringio
rake (13.0.6)
rake-compiler (1.1.9)
rake
rake-compiler-dock (1.2.1)
reline (0.2.5)
rake-compiler-dock (1.11.1)
rdoc (7.0.3)
erb
psych (>= 4.0.0)
tsort
reline (0.6.3)
io-console (~> 0.5)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rest-client (2.1.0-x64-mingw32)
ffi (~> 1.9)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
tzinfo (2.0.4)
ruby2_keywords (0.0.5)
stringio (3.2.0)
tsort (0.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
zeitwerk (2.4.2)
zeitwerk (2.6.18)

PLATFORMS
arm64-darwin-25
ruby
x64-mingw32
x64-mingw-ucrt

DEPENDENCIES
benchmark_driver (~> 0.15.9)
bundler (~> 2.2.15)
debase-ruby_core_source (~> 0.10.14)
bundler (>= 2.2.15)
csv
debase-ruby_core_source (>= 3.3.6)
excon (~> 0.73.0)
faraday (~> 1.0.1)
httparty (~> 0.18.0)
httpclient (~> 2.8.3)
irb
minitest (~> 5.14.4)
minitest (~> 5.16)
mongoid (~> 7.1.2)
multipart-post (~> 2.1.1)
mutex_m
ostruct
rake (~> 13.0.3)
rake-compiler (~> 1.1.1)
rake-compiler-dock (~> 1.2.1)
rake-compiler-dock (~> 1.11.0)
raygun-apm!
rest-client (~> 2.1.0)

BUNDLED WITH
2.2.33
4.0.3
188 changes: 187 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,188 @@
# raygun-apm-ruby
# raygun-apm

Ruby Profiler for Raygun Application Performance Monitoring.

This gem contains a C native extension that interfaces with the Ruby VM internals for method-level profiling. It communicates with the Raygun APM Agent over TCP/UDP to send trace data.

## Platform Gems

Each release produces **7 precompiled native gems** plus the source gem:

| # | Platform | OS | Architecture | Ruby Versions | Build Method |
|---|----------|----|-------------|---------------|--------------|
| 1 | `x86-mingw32` | Windows | 32-bit | 3.0 | rake-compiler-dock (Docker) |
| 2 | `x64-mingw32` | Windows | 64-bit | 3.0 | rake-compiler-dock (Docker) |
| 3 | `x64-mingw-ucrt` | Windows | 64-bit (UCRT) | 3.1, 3.2 | rake-compiler-dock (Docker) |
| 4 | `x86-linux` | Linux | 32-bit | 3.0, 3.1, 3.2 | rake-compiler-dock (Docker) |
| 5 | `x86_64-linux` | Linux | 64-bit | 3.0, 3.1, 3.2 | rake-compiler-dock (Docker) |
| 6 | `x86_64-darwin` | macOS | Intel | 3.0, 3.1, 3.2 | Native on macOS |
| 7 | `arm64-darwin` | macOS | Apple Silicon | 3.0, 3.1, 3.2 | Native on macOS |

**Note:** Windows Ruby 3.0 uses the `mingw32` platform. Ruby 3.1+ on Windows switched to UCRT (`x64-mingw-ucrt`). That's why there are separate Windows gems.

## Prerequisites

### For development (compile + test on your machine)

- Ruby 3.0, 3.1, or 3.2
- C compiler (GCC 12+ on Linux, Clang/Xcode on macOS)
- `debase-ruby_core_source` >= 3.3.6 (provides Ruby VM header files)
- System packages (Linux): `build-essential`, `libssl-dev`, `zlib1g-dev`, `libyaml-dev`

### For cross-compilation (building all platform gems)

- Docker (for rake-compiler-dock containers — builds Linux and Windows gems)
- macOS machine (for building the two darwin gems natively)
- Multiple Ruby versions installed via ruby-install, rbenv, or similar (for darwin cross-compile)

## Development Setup

```bash
git clone git@github.com:MindscapeHQ/raygun-apm-ruby.git
cd raygun-apm-ruby
bundle install
bundle exec rake compile # Compile native extension for your current Ruby
bundle exec rake test # Run the test suite
```

## Building Platform Gems

### Build all 7 platform gems (single command, requires Docker + macOS)

```bash
bundle exec rake gem:all
```

This runs `gem:native` (Docker) then `gem:native:darwin` (native) and produces all gems in `pkg/`.

### Step 1: Build Linux and Windows gems (Docker)

This uses `rake-compiler-dock` to cross-compile inside Docker containers. No Windows or Linux VM needed.

```bash
bundle exec rake gem:native
```

This builds all non-darwin platforms:
- `x86-mingw32` (Windows 32-bit, Ruby 3.0)
- `x64-mingw32` (Windows 64-bit, Ruby 3.0)
- `x64-mingw-ucrt` (Windows 64-bit UCRT, Ruby 3.1+)
- `x86-linux` (Linux 32-bit)
- `x86_64-linux` (Linux 64-bit)

Output goes to `pkg/`.

To build only Linux 64-bit:
```bash
bundle exec rake gem:linux
```

### Step 2: Build macOS gems (native, on a Mac)

Darwin gems **cannot** be cross-compiled in Docker — they must be built on an actual macOS machine.

**Prerequisite:** Install the target Ruby versions (e.g., via ruby-install):
```bash
ruby-install ruby 3.0.7
ruby-install ruby 3.1.7
ruby-install ruby 3.2.9
```

Then build:
```bash
./build-native-macos.sh
# or manually:
bundle exec rake gem:native:darwin
```

This produces:
- `x86_64-darwin` (Intel Mac)
- `arm64-darwin` (Apple Silicon)

Output goes to `pkg/`.

### Step 3: Verify

After both steps, `pkg/` should contain all 7 platform `.gem` files plus the source gem:
```
pkg/
raygun-apm-1.1.15.pre3.gem # source gem (compiles on install)
raygun-apm-1.1.15.pre3-x86-mingw32.gem
raygun-apm-1.1.15.pre3-x64-mingw32.gem
raygun-apm-1.1.15.pre3-x64-mingw-ucrt.gem
raygun-apm-1.1.15.pre3-x86-linux.gem
raygun-apm-1.1.15.pre3-x86_64-linux.gem
raygun-apm-1.1.15.pre3-x86_64-darwin.gem
raygun-apm-1.1.15.pre3-arm64-darwin.gem
```

## Running Tests

```bash
bundle exec rake test # Full test suite (requires compiled extension)
bundle exec rake compile # Just compile (no tests)
```

Tests require the native extension to be compiled first (`rake test` does this automatically via the `test => compile` dependency).

**Note:** Some tests (e.g., `apm_test.rb`) attempt to connect to a Raygun APM Agent. Tests that require an agent will raise `FatalError` and are expected to handle this gracefully.

## Release Process

1. Update version in `lib/raygun/apm/version.rb`
2. Build all platform gems (Steps 1 + 2 above)
3. Push each gem to RubyGems:
```bash
for gem in pkg/*.gem; do gem push "$gem"; done
```
4. Tag the release:
```bash
git tag v1.1.15.pre3
git push origin v1.1.15.pre3
```

## Project Structure

```
raygun-apm-ruby/
├── ext/raygun/ # C native extension source
│ ├── extconf.rb # Build configuration (mkmf)
│ ├── raygun_ext.c # Ruby C API entry point
│ ├── raygun_tracer.c/h # Core tracer (tracepoints, shadow stack)
│ ├── raygun_encoder.c/h # Binary event encoding
│ ├── raygun_event.c/h # Event types (HTTP, SQL, method calls)
│ ├── raygun_platform.c/h # Platform-specific code
│ ├── raygun_ringbuf.c/h # Lock-free ring buffer
│ ├── raygun_coercion.c/h # Ruby value coercion
│ ├── raygun_errors.c/h # Error handling
│ └── rax.c/h # Third-party radix tree (for blacklist)
├── lib/raygun/apm/
│ ├── tracer.rb # Ruby-side tracer (config, hooks, sinks)
│ ├── config.rb # Environment-based configuration
│ ├── diagnostics.rb # Agent connectivity checks + noop mode
│ ├── event.rb # Event type definitions
│ ├── version.rb # VERSION + MINIMUM_AGENT_VERSION
│ ├── blacklist.rb # Method blacklist filtering
│ └── hooks/ # Monkey-patches for HTTP clients, Redis, etc.
├── test/raygun/ # Minitest unit tests
├── Rakefile # Build tasks (compile, test, gem:native, etc.)
├── build-native-macos.sh # macOS build shortcut
├── build-native-win-linux.sh # Linux/Windows build (used in Vagrant/CI)
└── Vagrantfile # Ubuntu VM for Linux builds (alternative to Docker)
```

## Key Concepts

### Noop Mode

When the Raygun APM Agent is running but its version is below `MINIMUM_AGENT_VERSION` (defined in `version.rb`), the tracer enters **noop mode** via `tracer.noop!`. In this mode, all profiling is disabled to avoid overhead. The `raygun-apm-rails` middleware detects this via `tracer.noop?`.

### Native Extension

The C extension hooks into Ruby's TracePoint API and internal VM structures (via `debase-ruby_core_source` headers) to capture method calls, returns, and thread events with minimal overhead. Events are batched and sent to the Raygun Agent over UDP or TCP.

### Compiler Compatibility

- **GCC 12+**: Required `-Wno-use-after-free` for a false positive in third-party `rax.c`. Old-style C function definitions `()` updated to `(void)` for C99 compliance.
- **Clang**: Suppresses Clang-specific warnings (`-Wno-shorten-64-to-32`, etc.) that don't apply to GCC.
- `-Werror` is only enabled when `WERROR=1` or `CI=1` environment variable is set.
Loading