Getting Started with Instrument
View SourceThis guide will help you get started with the instrument library for metrics and tracing in your Erlang application.
Installation
rebar3
Add instrument to your rebar.config:
{deps, [
{instrument, "0.3.0"}
]}.mix (Elixir)
{:instrument, "~> 0.3.0"}Starting the Application
Instrument starts automatically when included as a dependency. You can also start it manually:
application:start(instrument).Your First Metrics
Counter
Counters track cumulative values that only increase (e.g., total requests):
%% Create a counter
Counter = instrument_metric:new_counter(http_requests_total, "Total HTTP requests"),
%% Increment by 1
instrument_metric:inc_counter(Counter),
%% Increment by a specific value
instrument_metric:inc_counter(Counter, 10),
%% Get current value
Value = instrument_metric:get_counter(Counter). %% Returns 11.0Gauge
Gauges track values that can go up or down (e.g., current connections):
%% Create a gauge
Gauge = instrument_metric:new_gauge(active_connections, "Current active connections"),
%% Set to a specific value
instrument_metric:set_gauge(Gauge, 100),
%% Increment/decrement
instrument_metric:inc_gauge(Gauge), %% Now 101
instrument_metric:dec_gauge(Gauge, 5), %% Now 96
%% Get current value
Value = instrument_metric:get_gauge(Gauge).Histogram
Histograms track distributions of values (e.g., request latencies):
%% Create with default buckets
Histogram = instrument_metric:new_histogram(request_duration_seconds, "Request duration"),
%% Create with custom buckets
Histogram2 = instrument_metric:new_histogram(response_size_bytes, "Response size",
[100, 500, 1000, 5000, 10000]),
%% Record observations
instrument_metric:observe_histogram(Histogram, 0.125),
instrument_metric:observe_histogram(Histogram, 0.250),
%% Get histogram data
#{count := Count, sum := Sum, buckets := Buckets} = instrument_metric:get_histogram(Histogram).Labeled Metrics (Vec API)
Add dimensions to your metrics with labels:
%% Create a counter with labels
instrument_metric:new_counter_vec(http_requests_total, "HTTP requests", [method, status]),
%% Increment specific label combinations
instrument_metric:inc_counter_vec(http_requests_total, ["GET", "200"]),
instrument_metric:inc_counter_vec(http_requests_total, ["POST", "201"]),
instrument_metric:inc_counter_vec(http_requests_total, ["GET", "404"]),
%% Get value for specific labels
Value = instrument_metric:get_counter_vec(http_requests_total, ["GET", "200"]).Prometheus Export
Export all metrics in Prometheus text format:
%% In your HTTP handler
handle_metrics_request(Req) ->
Body = instrument_prometheus:format(),
ContentType = instrument_prometheus:content_type(),
{200, [{<<"content-type">>, ContentType}], Body}.Your First Trace
Basic Span
%% Create a span around an operation
instrument_tracer:with_span(<<"process_order">>, fun() ->
%% Your code here
Order = fetch_order(OrderId),
process(Order)
end).Adding Indexable Attributes to Spans
Attributes are key-value pairs that get indexed by your observability backend, enabling filtering and querying:
instrument_tracer:with_span(<<"process_order">>, fun() ->
%% Add indexable attributes - these can be queried in Jaeger, Tempo, etc.
instrument_tracer:set_attributes(#{
%% String attributes
<<"order.id">> => OrderId,
<<"customer.id">> => CustomerId,
<<"customer.tier">> => <<"premium">>,
%% Numeric attributes (can filter by range)
<<"order.total">> => 149.99,
<<"order.item_count">> => 5,
%% Boolean attributes
<<"order.express">> => true
}),
%% Add timestamped events
instrument_tracer:add_event(<<"order_validated">>),
Result = process_order(Order),
%% Set status
instrument_tracer:set_status(ok),
Result
end).Now you can query traces in your backend:
- Find all orders from premium customers:
customer.tier = "premium" - Find expensive orders:
order.total > 100 - Find failed express orders:
order.express = true AND status = error
Nested Spans
instrument_tracer:with_span(<<"handle_request">>, fun() ->
%% Child span automatically linked to parent
instrument_tracer:with_span(<<"validate_input">>, fun() ->
validate(Input)
end),
instrument_tracer:with_span(<<"process_data">>, fun() ->
process(Data)
end),
instrument_tracer:with_span(<<"send_response">>, fun() ->
send(Response)
end)
end).Logger Integration
Automatically add trace context to your logs:
%% Install the logger integration (typically in your app start)
instrument_logger:install(),
%% Now all logs within spans include trace_id and span_id
instrument_tracer:with_span(<<"my_operation">>, fun() ->
logger:info("Processing request"), %% Includes trace context
do_work()
end).Next Steps
- Read the Instrumentation Guide for best practices
- Learn about Context Propagation for distributed tracing