Quickstart
This guide gets Unimeter running on your machine, then walks through defining a metric, sending a handful of events, and reading the usage total back. By the end you will have a working integration you can adapt to your real application.
What you need
Section titled “What you need”You need Docker installed to run the Unimeter server, and either Go or Python to run the client code.
Start Unimeter
Section titled “Start Unimeter”Clone the server repository, build the image, and start a single-node instance.
git clone https://github.com/unimeter/unimeter.gitcd serverdocker build -t unimeter .docker run -d --name unimeter -p 7001:7001 -p 9090:9090 unimeterThe build takes a minute or two on the first run. After that, Unimeter listens on port 7001 for application traffic and port 9090 for health checks. Verify it is alive by asking for its health status.
curl http://localhost:9090/healthA successful response looks like {"status":"ok","uptime_seconds":3}. If you see that, Unimeter is running and ready to accept events.
Set up the client
Section titled “Set up the client”Create a new project and install the Unimeter client library.
mkdir billing-demo && cd billing-demogo mod init billing-demogo get github.com/unimeter/go-unimeter@latestmkdir billing-demo && cd billing-demopython -m venv .venv && source .venv/bin/activatepip install unimeter-pythonDefine a metric
Section titled “Define a metric”A metric describes something you want to count, like API calls or bytes transferred. Before sending events, you tell Unimeter what the metric is called and how it should count. In this quickstart we define a metric called api_calls that simply counts one unit per event.
Create a file called main.go with the following content.
package main
import ( "context" "fmt" "log"
billing "github.com/unimeter/go-unimeter")
func main() { client, err := billing.New([]string{"localhost:7001"}) if err != nil { log.Fatal(err) } defer client.Close()
ctx := context.Background()
err = client.Metrics.Create(ctx, billing.MetricSchema{ Code: "api_calls", AggType: billing.AggCount, }) if err != nil { log.Fatal(err) } fmt.Println("metric created")}Run it with go run .. You should see metric created.
Create a file called main.py with the following content.
import asynciofrom unimeter import AsyncClient, MetricSchema, AggType
async def main(): async with AsyncClient(["localhost:7001"]) as client: await client.metrics.create(MetricSchema( code="api_calls", agg_type=AggType.COUNT, )) print("metric created")
asyncio.run(main())Run it with python main.py. You should see metric created.
If the metric already exists from a previous run, you can ignore the error; the call is safe to repeat.
Record some events
Section titled “Record some events”Now that the metric exists, send a few events. Three for account 1 and one for account 2.
Replace the body of main with the following, keeping the imports and the client setup at the top.
events := []billing.Event{ {AccountID: 1, MetricCode: "api_calls", Value: 1}, {AccountID: 1, MetricCode: "api_calls", Value: 1}, {AccountID: 1, MetricCode: "api_calls", Value: 1}, {AccountID: 2, MetricCode: "api_calls", Value: 1},}
result, err := client.Ingest(ctx, events)if err != nil { log.Fatal(err)}fmt.Printf("stored %d events\n", result.NStored)Run it with go run .. You should see stored 4 events.
Replace the body of main() with the following.
async with AsyncClient(["localhost:7001"]) as client: from unimeter import Event
result = await client.ingest([ Event(account_id=1, metric_code="api_calls", value=1), Event(account_id=1, metric_code="api_calls", value=1), Event(account_id=1, metric_code="api_calls", value=1), Event(account_id=2, metric_code="api_calls", value=1), ]) print(f"stored {result.n_stored} events")Run it with python main.py. You should see stored 4 events.
Unimeter persisted the events to disk, replicated them within the cluster (a cluster of one in this case), and updated its in-memory totals.
Read the usage back
Section titled “Read the usage back”Querying is the reverse of recording. You tell Unimeter which account and metric you care about, and for what period, and it returns the total.
Add this at the end of main.
usage, err := client.Query(ctx, billing.QueryRequest{ AccountID: 1, MetricCode: "api_calls", Period: billing.CurrentMonth(),})if err != nil { log.Fatal(err)}fmt.Printf("account 1 used api_calls %d times this month\n", usage.Value.Count)Run it again with go run ..
Add this inside the async with block.
from unimeter import current_month
usage = await client.query(1, "api_calls", current_month())print(f"account 1 used api_calls {usage.value.count} times this month")Run it again with python main.py.
The first three events from account 1 produced a total of three, matching what you sent. Account 2 sent one event, so querying for account 2 would return one.
This is the full loop. You defined a metric, sent events, and got a total back. Everything else you might want to do with Unimeter builds on this pattern.
Where to go from here
Section titled “Where to go from here”To understand the different counting modes (counting, summing, taking the maximum, tracking unique values), read Metric types.
To see how to tag events with dimensions like region or feature name and query them separately, read Filters and dimensions.
When you are ready to run Unimeter in production with multiple nodes and failover, see Running a cluster.
Clean up
Section titled “Clean up”When you are done experimenting, stop Unimeter and remove its data.
docker stop unimeter && docker rm unimeterThis removes the container that held your events.