Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
target/
.git/
*.md
!README.md
Cargo.lock
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Check
run: cargo check

- name: Test
run: cargo test

- name: Build
run: cargo build --release

# Test build on all platforms (without cross-compilation)
build-matrix:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]

runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Build
run: cargo build --release

- name: Test
run: cargo test
106 changes: 106 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Release

on:
push:
tags:
- 'v*'

jobs:
build:
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact: hydra-linux-x64
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
artifact: hydra-linux-arm64
cross: true
- os: macos-latest
target: x86_64-apple-darwin
artifact: hydra-darwin-x64
- os: macos-latest
target: aarch64-apple-darwin
artifact: hydra-darwin-arm64
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact: hydra-windows-x64.exe

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- name: Install cross (Linux ARM64)
if: matrix.cross
run: cargo install cross --git https://github.com/cross-rs/cross

- name: Build (cross)
if: matrix.cross
run: cross build --release --target ${{ matrix.target }}

- name: Build (native)
if: ${{ !matrix.cross }}
run: cargo build --release --target ${{ matrix.target }}

- name: Rename binary (Unix)
if: runner.os != 'Windows'
run: mv target/${{ matrix.target }}/release/hydra ${{ matrix.artifact }}

- name: Rename binary (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: Move-Item target/${{ matrix.target }}/release/hydra.exe ${{ matrix.artifact }}

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: ${{ matrix.artifact }}

release:
needs: build
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- uses: actions/checkout@v4

- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts

- name: List artifacts
run: find artifacts -type f

- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: artifacts/**/*
generate_release_notes: true

publish-npm:
needs: release
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Publish to npm
working-directory: npm
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Rust
/target/
Cargo.lock

# IDE
.idea/
.vscode/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Examples - Python
examples/python-fastapi/__pycache__/
examples/python-fastapi/*.pyc
examples/python-fastapi/.venv/
examples/python-fastapi/venv/

# Examples - Node
examples/node-express/node_modules/
examples/node-express/package-lock.json
42 changes: 42 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[package]
name = "hydra"
version = "0.1.0"
edition = "2021"
description = "Local-first dev observability. Zero config. Just works."
license = "MIT"

[dependencies]
# Async runtime
tokio = { version = "1", features = ["full"] }

# Web server
axum = { version = "0.7", features = ["ws"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["cors", "fs"] }

# OTLP / OpenTelemetry (using pre-built proto crates)
tonic = "0.12"
prost = "0.13"
prost-types = "0.13"
opentelemetry-proto = { version = "0.27", features = ["gen-tonic", "logs", "trace"] }

# Serialization
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# Utils
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "1", features = ["v4", "serde"] }
parking_lot = "0.12"
dashmap = "6"
anyhow = "1"
hex = "0.4"

# Embedded UI
rust-embed = { version = "8", features = ["axum"] }
mime_guess = "2"

[build-dependencies]
# No build deps needed - using opentelemetry-proto crate
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM rust:1.83-slim as builder

WORKDIR /app
COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/hydra /usr/local/bin/hydra
EXPOSE 8080 4317
CMD ["hydra"]
140 changes: 140 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
```
██╗ ██╗██╗ ██╗██████╗ ██████╗ █████╗
██║ ██║╚██╗ ██╔╝██╔══██╗██╔══██╗██╔══██╗
███████║ ╚████╔╝ ██║ ██║██████╔╝███████║
██╔══██║ ╚██╔╝ ██║ ██║██╔══██╗██╔══██║
██║ ██║ ██║ ██████╔╝██║ ██║██║ ██║
╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝

Local-first dev observability.
Zero config. Just works.
```

---

## What is this?

You're running microservices locally. Something's slow. Something's broken. You add `console.log`. You restart. You squint at terminal output. You cry.

**Hydra fixes this.**

One command. Full observability. Traces, logs, the works.

```bash
# No Rust? No problem.
npx hydra-dev

# Or install globally
npm install -g hydra-dev
hydra-dev

# Or with Docker
docker run -p 8080:8080 -p 4317:4317 ghcr.io/user/hydra

# Or build from source
cargo run --release
```

Open http://localhost:8080. Done.

---

## Quick Start

**1. Point your app at it**
```bash
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
```

**2. See everything**

Open http://localhost:8080

```
┌─────────────────────────────────────────────────────────────┐
│ HYDRA 12 traces · 47 logs │
├─────────────────────────────────────────────────────────────┤
│ [Traces] [Logs] [Services] [All Services ▼] │
├─────────────────────────────────────────────────────────────┤
│ 14:32:01 api-gateway POST /checkout 142ms │
│ 14:32:00 payment-svc ProcessPayment 89ms │
│ 14:31:58 api-gateway GET /users/123 12ms │
│ 14:31:55 inventory CheckStock 8ms │
└─────────────────────────────────────────────────────────────┘
```

Click any trace → see the full waterfall with correlated logs.

---

## Features

- **Zero config** — just run it
- **Single binary** — no Kafka, no Kubernetes, no YAML files
- **Auto-correlation** — logs linked to traces automatically
- **Ephemeral** — data lives in memory, restart clears it (feature, not bug)
- **Fast** — sub-second startup, minimal resource usage

---

## Endpoints

| Port | Protocol | Purpose |
|------|----------|---------|
| `8080` | HTTP | Web UI + REST API |
| `4317` | gRPC | OTLP receiver |

---

## API

```bash
GET /api/traces/:id # Get trace with spans + logs
GET /api/spans # Recent spans
GET /api/logs # Recent logs
GET /api/services # Discovered services
GET /health # Health check
```

---

## Examples

```bash
# Python FastAPI
cd examples/python-fastapi
pip install -r requirements.txt
python app.py

# Node.js Express (auto-generates traffic)
cd examples/node-express
npm install && npm start
```

---

## Philosophy

```
Production has Datadog.
Local dev has println.

This is the missing middle.
```

Hydra is **not** for production. It's for your laptop. It's for `docker-compose up`. It's for "why is this endpoint slow?" without deploying to staging.

---

## Tech

- Rust + Tokio
- OTLP over gRPC
- In-memory ring buffers
- Embedded web UI

---

## License

MIT
8 changes: 8 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
hydra:
build: .
ports:
- "8080:8080" # Web UI
- "4317:4317" # OTLP gRPC
environment:
- RUST_LOG=info
Loading