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
16 changes: 15 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ $(BUF):
MDOX = mdox
$(MDOX):
@go install github.com/bwplotka/mdox@latest

# Hacky, replace the binary path for yourself for now.
# One could use docker as well. TODO: Fix this.
WEAVER = ../otel-weaver/target/debug/weaver

# ------

.PHONY: help
help: ## Display this help and any documented user-facing targets. Other undocumented targets may be present in the Makefile.
help:
@awk 'BEGIN {FS = ": ##"; printf "Usage:\n make <target>\n\nTargets:\n"} /^[a-zA-Z0-9_\.\-\/%]+: ##/ { printf " %-45s %s\n", $$1, $$2 }' $(MAKEFILE_LIST)


.PHONY: docker
docker:
@export DOCKER_IMAGE=$(DOCKER_IMAGE) DOCKER_TAG=$(DOCKER_TAG) && bash scripts/build-docker.sh $(DOCKER_PUSH)
Expand All @@ -49,3 +53,13 @@ format: $(GOFUMPT) $(GOIMPORTS) $(MDOX)
@echo ">> format documentation"
@$(MDOX) fmt --soft-wraps ./*.md

SEMCONV_VERSION ?= v0.1.0
.PHONY: gen # Generate artefacts e.g. metric definitions from my-org semconv.
gen:
@echo ">> weaver generate"
@$(WEAVER) registry generate \
--registry=./my-org/semconv/$(SEMCONV_VERSION) \
--templates=./client_golang/semconv \
go \
./go/my-app/semconv/$(SEMCONV_VERSION)

87 changes: 87 additions & 0 deletions client_golang/semconv/registry/go/metric.go.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{%- set my_file_name = ctx.metric_name | lower | snake_case ~ ".go" -%}
{{- template.set_file_name(my_file_name) -}}
{% set construct_name = ctx.id.split('.')[-1] %}
{%- set instrToVecTypes = {
'counter': "CounterVec",
'gauge': "GaugeVec",
}-%}
{%- set instrToOptTypes = {
'counter': "CounterOpts",
'gauge': "GaugeOpts",
}-%}
{%- set labelTypeToTypes = {
'string': "string",
'int': "int",
'double': "float64",
}-%}
{% macro const_label_type(label) -%}
{{ construct_name | pascal_case ~ label.tag | pascal_case }}
{%- endmacro %}
// Copyright 2025 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Code generated from semantic convention specification. DO NOT EDIT.

package semconv // TODO(bwplotka): Use id prefix or something more unique?

import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)

{%- for label in ctx.attributes -%}
{%- if label.type.members is defined %}

type {{ const_label_type(label) }} string

const (
{%- for value in label.type.members %}
{{ value.id | pascal_case }}{{ const_label_type(label) }} {{ const_label_type(label) }} = "{{ value.value }}"
{%- endfor %}
)
{%- endif %}
{%- endfor %}

func MustNew{{ construct_name | pascal_case }}{{ ctx.instrument | pascal_case }}Vec(reg prometheus.Registerer) *prometheus.{{ instrToVecTypes[ctx.instrument] }} {
return promauto.With(reg).New{{ instrToVecTypes[ctx.instrument] }}(prometheus.{{ instrToOptTypes[ctx.instrument] }}{
Name: "{{ ctx.metric_name }}",
{% if ctx.note is defined -%}
Help: "{{ ctx.note }}",
{% else -%}
Help: "{{ ctx.brief }}",
{%- endif %}
// Unit: "{{ ctx.unit }}" // TODO(bwplotka): Add Unit as one of the supported options.
}, []string{
{%- for label in ctx.attributes %}
"{{label.tag}}",
{%- endfor %}
})
}

/*
TODO(bwplotka): Add more type safety e.g. for CustomElementsCounterVec:

type CustomElementsCounterVec struct {
prometheus.CounterVec
}

func (v *CustomElementsCounterVec) WithLabelValues(integer int, category CustomElementsCategory, fraction float64) prometheus.Counter {
// This is not ideal as we do, potentially expensive stringifying on the hot path.
// Fix might require internals to completely differ in the client_golang for the efficient solution.
return v.CounterVec.WithLabelValues(fmt.Sprintf("%v", integer), string(category), fmt.Sprintf("%v", fraction))
}
*/




17 changes: 17 additions & 0 deletions client_golang/semconv/registry/go/weaver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
templates:
- template: metric.go.j2
filter: >
.groups
| map(select(.type == "metric"))
| sort_by(.metric_name)
application_mode: each

comment_formats:
go:
format: markdown
prefix: "// "
indent_first_level_list_items: true
shortcut_reference_link: true
trim: true
remove_trailing_dots: true
default_comment_format: go
19 changes: 13 additions & 6 deletions go/my-app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package main
import (
"context"
"flag"
"log"
"log/slog"
"net/http"
"os"
"syscall"

semconv "github.com/bwplotka/metric-rename-demo/go/my-app/my-app/semconv/v0.1.0"
"github.com/nelkinda/health-go"
"github.com/oklog/run"
"github.com/prometheus/client_golang/prometheus"
Expand All @@ -18,6 +20,7 @@ import (

func main() {
addrFlag := flag.String("listen-address", ":9011", "Address to listen on. Available HTTP paths: /metrics")
metricDefinition := flag.String("metric-source", "manual", "Metric definition source to use ['manual', 'generated@v0.1.0'")
flag.Parse()

reg := prometheus.NewRegistry()
Expand All @@ -26,12 +29,16 @@ func main() {
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
)

customStableMetric := promauto.With(reg).NewCounterVec(prometheus.CounterOpts{
Name: "my_app_custom_counter_total",
Help: "Custom counter metric for my app counts important things. It serves as an example " +
"of a very important metric that everyone is using.",
}, []string{"integer", "category", "fraction"})
customStableMetric.WithLabelValues("101", "AType", "1.22314").Inc()
switch *metricDefinition {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hope the intention is clear. This binary will help us showcase the case of e.g. same type of container runs with different versions where metric name changed between e.g.

my-app -metric-source=generated@v0.1.0
my-app -metric-source=generated@v0.2.0

case "manual":
m := mustNewCustomStableMetric(reg)
m.WithLabelValues("101", "a", "1.22314").Inc()
case "generated@v0.1.0":
m := semconv.MustNewCustomElementsCounterVec(reg)
m.WithLabelValues("101", string(semconv.ACustomElementsCategory), "1.22314").Inc() // TODO(bwplotka): Make it more type safe.
default:
log.Fatalf("unknown -metric-source source, got %v", *metricDefinition)
}

var g run.Group
{
Expand Down
14 changes: 14 additions & 0 deletions go/my-app/manual.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)

func mustNewCustomStableMetric(reg prometheus.Registerer) *prometheus.CounterVec {
return promauto.With(reg).NewCounterVec(prometheus.CounterOpts{
Name: "my_app_custom_elements_total",
Help: "Custom counter metric for my app counting important elements. It serves as an example " +
"of a very important metric that everyone is using.",
}, []string{"integer", "category", "fraction"})
}
59 changes: 59 additions & 0 deletions go/my-app/semconv/v0.1.0/my_app_custom_elements_total.go

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

48 changes: 48 additions & 0 deletions go/my-app/semconv/v0.1.0/my_app_some_elements_total.go

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

45 changes: 45 additions & 0 deletions my-org/semconv/v0.1.0/my-app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Schema: https://github.com/open-telemetry/weaver/blob/main/schemas/semconv.schema.json
groups:
- id: metric.my-org.custom_elements
type: metric
metric_name: my_app_custom_elements_total
brief: "Custom counter metric for my app counting important elements. It serves as an example of a very important metric that everyone is using."
instrument: counter
# Unit schema: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/metrics.md#instrument-units
# It comes from https://unitsofmeasure.org/ucum standard.
unit: "{elements}"
attributes:
- id: metric.my-org.custom_elements.integer
tag: "integer"
type: int
brief: |
This is an important label that specifies the integer for this count.
- id: metric.my-org.custom_elements.category
tag: "category"
type:
members:
- id: a
value: "a"
stability: stable
- id: b
value: "b"
stability: stable
- id: other
value: "other"
stability: stable
brief: |
This is an important label that specifies the category for this count.
- id: metric.my-org.custom_elements.fraction
tag: "fraction"
type: double
brief: |
This is an important label that specifies the fraction for this count.
stability: stable
- id: metric.my-org.some_elements
type: metric
metric_name: my_app_some_elements_total
deprecated: "Deprecated, not needed anymore"
brief: "old metric"
instrument: counter
unit: "{unknown}"
stability: experimental