How to Configure Real-Time Cost Tracking and Per-Request Cost Breakdown in AxonHub

AxonHub automatically calculates monetary costs for every LLM request by mapping token usage against configurable per-model pricing, storing granular breakdowns in the usage_logs table and exposing them via GraphQL.

AxonHub is an open-source LLM gateway that provides centralized request management and observability. To configure real-time cost tracking and per-request cost breakdown, you must define model-specific pricing in ChannelModelPrice records, enable the automatic cost computation pipeline, and query the exposed GraphQL fields. This guide walks through the exact configuration steps using the actual source implementation.

Define Model Pricing in ChannelModelPrice

AxonHub stores model-specific pricing in the ChannelModelPrice entity. The server loads these prices at startup from your configuration file or via the business logic layer.

In internal/server/biz/channel_price.go, the CreateChannelModelPrice function persists pricing entries.

Configuration via YAML

Add pricing definitions to your conf/example.yml:

channel_models:
  - channel_id: "default"
    model_id: "gpt-4o"
    price:
      prompt_tokens: 0.00001
      completion_tokens: 0.00002
    reference_id: "openai-2024-04"

Programmatic Configuration

To create pricing entries via the Go SDK, use the CreateChannelModelPrice method in internal/server/biz/channel_price.go:

price := objects.ModelPrice{
    PromptTokens:      0.00001,
    CompletionTokens:  0.00002,
    ReferenceID: "openai-2024-04",
}
ctx := context.Background()
_, err := channelPriceService.CreateChannelModelPrice(ctx, channelID, modelID, price)
if err != nil {
    log.Fatalf("cannot create price: %v", err)
}

Enable Automatic Cost Computation

Cost is calculated in internal/server/biz/cost_calc.go using the ComputeUsageCost function:

func ComputeUsageCost(usage *objects.Usage, price objects.ModelPrice) (items []objects.CostItem, total float64)

The function is called from internal/server/biz/usage_log.go after a request finishes:

costItems, totalCost, priceReferenceID = s.computeUsageCost(
    ctx, params.ChannelID, params.ActualModelID, params.Usage)
mut = mut.SetCost(totalCost).SetCostItems(costItems).SetCostPriceReferenceID(priceReferenceID)

The server always attempts to find a price for the model. Ensure a ChannelModelPrice exists for the model and channel combination. The cost fields are stored in the usage_logs table columns total_cost, cost_items, and cost_price_reference_id.

Query Per-Request Cost Breakdown via GraphQL

AxonHub exposes cost data through its GraphQL API defined in internal/server/gql/cost.graphql.

The UsageLog type includes:

type UsageLog {
  id: ID!
  requestID: ID!
  totalCost: Float!
  costItems: [CostItem!]!
  costPriceReferenceID: String
}

Each CostItem provides granular detail:

type CostItem {
  name: String!
  units: Float!
  pricePerUnit: Float!
  cost: Float!
}

Fetch a specific request's cost breakdown:

query GetUsageCost($id: ID!) {
  usageLog(id: $id) {
    totalCost
    costItems {
      name
      units
      pricePerUnit
      cost
    }
    costPriceReferenceID
  }
}

Real-Time Dashboard Aggregation

For real-time cost tracking across all requests, the dashboard resolver in internal/server/gql/dashboard.resolvers.go aggregates daily totals.

It queries the usage_logs table using:

sql.As(fmt.Sprintf("COALESCE(SUM(%s), 0)", s.C(usagelog.FieldTotalCost)), "total_cost")

The DailyRequestStats GraphQL type returns:

type DailyRequestStats {
  period: Date!
  requests: Int!
  totalTokens: Int!
  cost: Float!
}

Query for dashboard data:

query DailyStats($start: Date!, $end: Date!) {
  dailyRequestStats(start: $start, end: $end) {
    period
    requests
    totalTokens
    cost
  }
}

Verify Your Configuration

Follow these steps to confirm real-time cost tracking is active:

  1. Define pricing for your target model in conf/example.yml or via the API using CreateChannelModelPrice.
  2. Send a test request through AxonHub to the configured model.
  3. Query the usage log using the GraphQL API to verify totalCost and costItems are populated.
  4. Check the dashboard at /dashboard to see the aggregated cost reflect in the daily statistics.

Summary

Frequently Asked Questions

How does AxonHub calculate costs for different token types?

AxonHub's ComputeUsageCost function in internal/server/biz/cost_calc.go multiplies the token count for each category—such as prompt_tokens, completion_tokens, vision_tokens, or audio_tokens—by the corresponding price defined in the ChannelModelPrice entry. The function returns both the total cost and an itemized list of CostItem objects detailing each calculation.

Can I update pricing without restarting the server?

Yes. While the server loads initial pricing from conf/example.yml at startup, you can create or update ChannelModelPrice records programmatically using the CreateChannelModelPrice method in internal/server/biz/channel_price.go. New requests immediately use the updated pricing without requiring a restart, as the cost calculation logic queries the database for the current price at request time.

Where is the per-request cost data stored?

Per-request cost data is persisted in the usage_logs table with three specific columns: total_cost stores the aggregated monetary value, cost_items contains a JSON array of detailed CostItem objects, and cost_price_reference_id records which ChannelModelPrice version was used for the calculation. This schema is defined in the ent schema files and handled by the persistence layer in internal/server/biz/usage_log.go.

How do I query total daily costs for billing purposes?

Use the dailyRequestStats GraphQL query defined in internal/server/gql/dashboard.resolvers.go. This resolver aggregates the total_cost column from the usage_logs table using SQL's SUM function, grouped by day. The query returns a DailyRequestStats type containing the period, requests, totalTokens, and cost fields, allowing you to generate daily or monthly billing reports directly from the API.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →