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
3 changes: 0 additions & 3 deletions .mise.toml

This file was deleted.

47 changes: 47 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# AGENTS.md

## Commands

```
go build -o opensloctl . # build binary
go run . load -f <file> # parse and print OpenSlo specs
go run . generate -f <file> -o <dir> # generate Prometheus recording rules
golangci-lint run # lint (via mise)
go test ./... # run tests (none exist yet)
```

## Architecture

- `main.go` → `cmd.Execute()` — single entrypoint
- CLI: cobra-based, two subcommands: `load`, `generate`
- `pkg/specstore/` — loads and sorts OpenSlo YAML files into typed structs
- `internal/generator/prometheusgenerator/` — generates Prometheus recording rule YAML from SLO specs using Go templates (embedded via `//go:embed`)
- `pkg/semconv/` — OpenTelemetry semantic convention constants
- `internal/feature/` — feature flags (multi-dimensional SLI annotations)
- `pkg/util/file.go` — file discovery (recursive YAML/YML finder)

## Key Dependencies

- `github.com/thisisibrahimd/openslo` — OpenSlo SDK for decoding specs
- `github.com/spf13/cobra` — CLI framework
- `github.com/charmbracelet/log` — logging
- `github.com/Masterminds/sprig/v3` — template functions

## CI / Release

- GoReleaser builds linux/darwin binaries, CGO_ENABLED=0
- PR triggers snapshot dry-run; published release triggers real release
- `go mod tidy` + `go generate ./...` run before build

## Tooling

- `mise.toml` manages Go (1.26), golangci-lint, weaver
- No `.golangci.yml` — uses defaults
- No Makefile, Taskfile, or pre-commit hooks

## Gotchas

- `generate` requires `-o` (output directory) — cannot be empty
- `generate` requires `indicator` on SLOs; ratio metrics not supported
- Spec files must be YAML/YML; non-OpenSlo files are silently skipped with a log error
- No tests exist — adding tests requires setting up from scratch
46 changes: 46 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
REGISTRY_DIR := semconv/registry

.PHONY: semconv-generate
semconv-generate:
weaver registry generate --v2 --registry $(REGISTRY_DIR) --templates ./semconv/templates/ go ./pkg/semconv/
gofmt -w ./pkg/semconv/semconv_gen.go

.PHONY: semconv-check
semconv-check:
weaver registry check --v2 -r $(REGISTRY_DIR)

.PHONY: semconv-stats
semconv-stats:
weaver registry stats -r $(REGISTRY_DIR)

.PHONY: semconv-json
semconv-json:
weaver registry json-schema -r $(REGISTRY_DIR)

.PHONY: semconv-diff
semconv-diff:
weaver registry diff --v2 --registry $(REGISTRY_DIR) --baseline-registry $(REGISTRY_DIR)@$(BASE)

.PHONY: build
build:
go build -o opensloctl .

.PHONY: lint
lint:
golangci-lint run

.PHONY: test
test:
go test ./...

.PHONY: generate
generate:
go run . generate -f $(FILE) -o $(OUTPUT)

.PHONY: load
load:
go run . load -f $(FILE)

.PHONY: tidy
tidy:
go mod tidy
157 changes: 157 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# opensloctl

Generate Prometheus recording rules from OpenSlo specs.

## Installation

### Via mise (GitHub backend)

If you use [mise](https://mise.jdx.dev/), you can install opensloctl directly from GitHub releases:

```
mise use github:thisisibrahimd/opensloctl
```

This adds the tool to your local `mise.toml` and installs the latest release binary. After that, `opensloctl` is available on your PATH within the project.

### From source

```
go install github.com/thisisibrahimd/opensloctl@latest
```

Or clone and build:

```
git clone https://github.com/thisisibrahimd/opensloctl.git
cd opensloctl
go build -o opensloctl .
```

## Development

This project uses [mise](https://mise.jdx.dev/) to manage tool versions (Go, golangci-lint, Weaver).

### Install mise

See [mise installation docs](https://mise.jdx.dev/getting-started.html).

### Install project tools

Once mise is installed, run this in the repo root:

```
mise install
```

This installs the exact versions declared in `mise.toml`:
- **Go** 1.26
- **golangci-lint** (latest)
- **Weaver** (latest) — for semantic convention registry management

After installing, commands like `go`, `golangci-lint`, and `weaver` are available automatically in the project directory.

## Commands

```
go build -o opensloctl . # build binary
go run . load -f <file> # parse and print OpenSlo specs
go run . generate -f <file> -o <dir> # generate Prometheus recording rules
make semconv-generate # regenerate semconv_gen.go from registry
make semconv-check # validate registry schema
make lint # run golangci-lint
make test # run go test ./...
```

## Semantic Conventions

opensloctl defines a registry of metrics and attributes for SLO telemetry. The registry lives in `semconv/registry/` and is used to generate `pkg/semconv/semconv_gen.go`.

### Attributes

| Attribute | Type | Description |
|---|---|---|
| `openslo.slo.name` | string | The name of the SLO as defined in the OpenSlo spec. |
| `openslo.spec.version` | string | The OpenSlo API version of the SLO spec. |

### Metrics

#### SLO Info

| Metric | Type | Unit | Description |
|---|---|---|---|
| `openslo.slo.info` | gauge | 1 | Identifies the existence of an SLO. Always has value 1. |
| `openslo.slo.objective` | gauge | 1 | The target SLI objective (e.g., 0.999 for 99.9% availability). |
| `openslo.slo.timewindow_days` | gauge | 1 | The SLO time window duration expressed as a number of days. |
| `openslo.slo.error_budget` | gauge | 1 | The error budget calculated as 1 minus the objective. |

All SLO info metrics carry `openslo.slo.name` and `openslo.spec.version` labels.

#### SLI Error Rate

| Metric | Description |
|---|---|
| `openslo.sli.error_rate_5m` | SLI error rate over a 5-minute window. |
| `openslo.sli.error_rate_30m` | SLI error rate over a 30-minute window. |
| `openslo.sli.error_rate_1h` | SLI error rate over a 1-hour window. |
| `openslo.sli.error_rate_2h` | SLI error rate over a 2-hour window. |
| `openslo.sli.error_rate_6h` | SLI error rate over a 6-hour window. |
| `openslo.sli.error_rate_1d` | SLI error rate over a 1-day window. |
| `openslo.sli.error_rate_3d` | SLI error rate over a 3-day window. |
| `openslo.sli.error_rate_7d` | SLI error rate over a 7-day window. |
| `openslo.sli.error_rate_28d` | SLI error rate over a 28-day window. |
| `openslo.sli.error_rate_30d` | SLI error rate over a 30-day window. |

All error rate metrics carry `openslo.slo.name` and `openslo.spec.version` labels.

### Registry Management

The semantic convention registry is managed with [OpenTelemetry Weaver](https://github.com/open-telemetry/weaver).

- **Registry source**: `semconv/registry/` — YAML definitions for attributes and metrics
- **Generated code**: `pkg/semconv/semconv_gen.go` — auto-generated Go constants from the registry
- **Templates**: `semconv/templates/go/` — MiniJinja templates that produce the Go file

```
make semconv-generate # regenerate semconv_gen.go from registry
make semconv-check # validate registry schema
make semconv-stats # show registry statistics
make semconv-diff BASE=<ref> # detect breaking changes vs a base ref
```

### Consuming the Registry

If your project also uses OpenTelemetry Weaver, you can depend on this registry directly. Add it as a dependency in your `manifest.yaml`:

```yaml
schema_url: https://your-org.com/schemas/your-app/v1.0.0

dependencies:
- schema_url: https://openslo.com/schemas/v1.0.0
registry_path: https://github.com/thisisibrahimd/opensloctl.git[semconv/registry]
```

Then reference the attributes in your own metrics and spans:

```yaml
metrics:
- name: myapp.slo.burn_rate
instrument: gauge
unit: "1"
stability: development
brief: Current error budget burn rate.
attributes:
- ref: openslo.slo.name
requirement_level: required
- ref: openslo.spec.version
requirement_level: required
```

Alternatively, if you don't use Weaver, the Go constants are available at `github.com/thisisibrahimd/opensloctl/pkg/semconv`:

```go
import "github.com/thisisibrahimd/opensloctl/pkg/semconv"

// Use generated constants
meter.Float64ObservableGauge(semconv.METRIC_OPENSLO_SLO_INFO)
```
4 changes: 4 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[tools]
go = "1.26"
golangci-lint = "latest"
"github:open-telemetry/weaver" = "latest"
23 changes: 0 additions & 23 deletions pkg/semconv/semconv.go

This file was deleted.

68 changes: 68 additions & 0 deletions pkg/semconv/semconv_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions semconv/registry/attributes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
file_format: definition/2

attributes:
- key: openslo.slo.name
type: string
stability: development
brief: The name of the SLO as defined in the OpenSlo spec.

- key: openslo.spec.version
type: string
stability: development
brief: The OpenSlo API version of the SLO spec.

- key: openslo.objective.decimal
type: double
stability: development
brief: The SLO objective expressed as a decimal value (e.g., 0.999).

- key: openslo.objective.percent
type: double
stability: development
brief: The SLO objective expressed as a percentage (e.g., 99.9).

- key: openslo.service.name
type: string
stability: development
brief: The name of the service the SLO belongs to.

- key: openslo.timewindow.duration
type: string
stability: development
brief: The time window duration for the SLO (e.g., 28d).
2 changes: 2 additions & 0 deletions semconv/registry/manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$schema: https://raw.githubusercontent.com/open-telemetry/weaver/main/schemas/manifest.json
schema_url: https://openslo.com/schemas/v1.0.0
Loading
Loading