Просмотр исходного кода

fmt

Signed-off-by: Sean Holcomb <seanholcomb@gmail.com>
Sean Holcomb 20 часов назад
Родитель
Сommit
76766de780

+ 2 - 0
justfile

@@ -12,6 +12,8 @@ fmt:
     cd ./core && go fmt ./...
     cd ./core && go fmt ./...
     cd ./modules/collector-source && go fmt ./...
     cd ./modules/collector-source && go fmt ./...
     cd ./modules/prometheus-source && go fmt ./...
     cd ./modules/prometheus-source && go fmt ./...
+    cd ./modules/pricing/basic && go fmt ./...
+    cd ./modules/pricing/public && go fmt ./...
 
 
 # check if code is formatted
 # check if code is formatted
 fmt-check:
 fmt-check:

+ 0 - 1
modules/collector-source/pkg/collector/metricsquerier.go

@@ -749,7 +749,6 @@ func (c *collectorMetricsQuerier) QueryDataCoverage(limitDays int) (time.Time, t
 	return c.collectorProvider.GetDailyDataCoverage(limitDays)
 	return c.collectorProvider.GetDailyDataCoverage(limitDays)
 }
 }
 
 
-
 // Inference cost methods - not supported by collector source (only available via Prometheus)
 // Inference cost methods - not supported by collector source (only available via Prometheus)
 func (c *collectorMetricsQuerier) QueryInferencePromptTokens(start, end time.Time) *source.Future[source.InferenceTokensResult] {
 func (c *collectorMetricsQuerier) QueryInferencePromptTokens(start, end time.Time) *source.Future[source.InferenceTokensResult] {
 	ch := make(source.QueryResultsChan, 1)
 	ch := make(source.QueryResultsChan, 1)

+ 1 - 1
modules/pricing/public/azure/azurepricingsource_test.go

@@ -344,7 +344,7 @@ func TestNewAzurePricingSource(t *testing.T) {
 
 
 // Helper function to check if a string contains a substring
 // Helper function to check if a string contains a substring
 func contains(s, substr string) bool {
 func contains(s, substr string) bool {
-	return len(s) >= len(substr) && (s == substr || len(substr) == 0 || 
+	return len(s) >= len(substr) && (s == substr || len(substr) == 0 ||
 		(len(s) > 0 && (s[0:len(substr)] == substr || contains(s[1:], substr))))
 		(len(s) > 0 && (s[0:len(substr)] == substr || contains(s[1:], substr))))
 }
 }
 
 

+ 30 - 30
modules/prometheus-source/pkg/prom/inference_queries.go

@@ -13,10 +13,10 @@ import (
 // QueryInferencePromptTokens implements MetricsQuerier.QueryInferencePromptTokens
 // QueryInferencePromptTokens implements MetricsQuerier.QueryInferencePromptTokens
 func (pds *PrometheusMetricsQuerier) QueryInferencePromptTokens(start, end time.Time) *source.Future[source.InferenceTokensResult] {
 func (pds *PrometheusMetricsQuerier) QueryInferencePromptTokens(start, end time.Time) *source.Future[source.InferenceTokensResult] {
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
-	
+
 	// Create a channel for the async result
 	// Create a channel for the async result
 	resultsChan := make(source.QueryResultsChan, 1)
 	resultsChan := make(source.QueryResultsChan, 1)
-	
+
 	// Execute query asynchronously
 	// Execute query asynchronously
 	go func() {
 	go func() {
 		values, err := queryCounterDelta(ctx, "vllm:prompt_tokens_total", start, end)
 		values, err := queryCounterDelta(ctx, "vllm:prompt_tokens_total", start, end)
@@ -24,112 +24,112 @@ func (pds *PrometheusMetricsQuerier) QueryInferencePromptTokens(start, end time.
 			resultsChan <- &source.QueryResults{Error: err}
 			resultsChan <- &source.QueryResults{Error: err}
 			return
 			return
 		}
 		}
-		
+
 		// Convert map to QueryResults format
 		// Convert map to QueryResults format
 		results := mapToQueryResults(values)
 		results := mapToQueryResults(values)
 		resultsChan <- &source.QueryResults{Results: results}
 		resultsChan <- &source.QueryResults{Results: results}
 	}()
 	}()
-	
+
 	return source.NewFuture(decodeInferenceTokensResult, resultsChan)
 	return source.NewFuture(decodeInferenceTokensResult, resultsChan)
 }
 }
 
 
 // QueryInferenceGenerationTokens implements MetricsQuerier.QueryInferenceGenerationTokens
 // QueryInferenceGenerationTokens implements MetricsQuerier.QueryInferenceGenerationTokens
 func (pds *PrometheusMetricsQuerier) QueryInferenceGenerationTokens(start, end time.Time) *source.Future[source.InferenceTokensResult] {
 func (pds *PrometheusMetricsQuerier) QueryInferenceGenerationTokens(start, end time.Time) *source.Future[source.InferenceTokensResult] {
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
-	
+
 	resultsChan := make(source.QueryResultsChan, 1)
 	resultsChan := make(source.QueryResultsChan, 1)
-	
+
 	go func() {
 	go func() {
 		values, err := queryCounterDelta(ctx, "vllm:generation_tokens_total", start, end)
 		values, err := queryCounterDelta(ctx, "vllm:generation_tokens_total", start, end)
 		if err != nil {
 		if err != nil {
 			resultsChan <- &source.QueryResults{Error: err}
 			resultsChan <- &source.QueryResults{Error: err}
 			return
 			return
 		}
 		}
-		
+
 		results := mapToQueryResults(values)
 		results := mapToQueryResults(values)
 		resultsChan <- &source.QueryResults{Results: results}
 		resultsChan <- &source.QueryResults{Results: results}
 	}()
 	}()
-	
+
 	return source.NewFuture(decodeInferenceTokensResult, resultsChan)
 	return source.NewFuture(decodeInferenceTokensResult, resultsChan)
 }
 }
 
 
 // QueryInferenceInputProcessingTime implements MetricsQuerier.QueryInferenceInputProcessingTime
 // QueryInferenceInputProcessingTime implements MetricsQuerier.QueryInferenceInputProcessingTime
 func (pds *PrometheusMetricsQuerier) QueryInferenceInputProcessingTime(start, end time.Time) *source.Future[source.InferenceProcessingTimeResult] {
 func (pds *PrometheusMetricsQuerier) QueryInferenceInputProcessingTime(start, end time.Time) *source.Future[source.InferenceProcessingTimeResult] {
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
-	
+
 	resultsChan := make(source.QueryResultsChan, 1)
 	resultsChan := make(source.QueryResultsChan, 1)
-	
+
 	go func() {
 	go func() {
 		values, err := queryCounterDelta(ctx, "vllm:request_prefill_time_seconds_sum", start, end)
 		values, err := queryCounterDelta(ctx, "vllm:request_prefill_time_seconds_sum", start, end)
 		if err != nil {
 		if err != nil {
 			resultsChan <- &source.QueryResults{Error: err}
 			resultsChan <- &source.QueryResults{Error: err}
 			return
 			return
 		}
 		}
-		
+
 		results := mapToQueryResults(values)
 		results := mapToQueryResults(values)
 		resultsChan <- &source.QueryResults{Results: results}
 		resultsChan <- &source.QueryResults{Results: results}
 	}()
 	}()
-	
+
 	return source.NewFuture(decodeInferenceProcessingTimeResult, resultsChan)
 	return source.NewFuture(decodeInferenceProcessingTimeResult, resultsChan)
 }
 }
 
 
 // QueryInferenceOutputProcessingTime implements MetricsQuerier.QueryInferenceOutputProcessingTime
 // QueryInferenceOutputProcessingTime implements MetricsQuerier.QueryInferenceOutputProcessingTime
 func (pds *PrometheusMetricsQuerier) QueryInferenceOutputProcessingTime(start, end time.Time) *source.Future[source.InferenceProcessingTimeResult] {
 func (pds *PrometheusMetricsQuerier) QueryInferenceOutputProcessingTime(start, end time.Time) *source.Future[source.InferenceProcessingTimeResult] {
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
-	
+
 	resultsChan := make(source.QueryResultsChan, 1)
 	resultsChan := make(source.QueryResultsChan, 1)
-	
+
 	go func() {
 	go func() {
 		values, err := queryCounterDelta(ctx, "vllm:request_time_per_output_token_seconds_sum", start, end)
 		values, err := queryCounterDelta(ctx, "vllm:request_time_per_output_token_seconds_sum", start, end)
 		if err != nil {
 		if err != nil {
 			resultsChan <- &source.QueryResults{Error: err}
 			resultsChan <- &source.QueryResults{Error: err}
 			return
 			return
 		}
 		}
-		
+
 		results := mapToQueryResults(values)
 		results := mapToQueryResults(values)
 		resultsChan <- &source.QueryResults{Results: results}
 		resultsChan <- &source.QueryResults{Results: results}
 	}()
 	}()
-	
+
 	return source.NewFuture(decodeInferenceProcessingTimeResult, resultsChan)
 	return source.NewFuture(decodeInferenceProcessingTimeResult, resultsChan)
 }
 }
 
 
 // QueryInferenceCachedTokens implements MetricsQuerier.QueryInferenceCachedTokens
 // QueryInferenceCachedTokens implements MetricsQuerier.QueryInferenceCachedTokens
 func (pds *PrometheusMetricsQuerier) QueryInferenceCachedTokens(start, end time.Time) *source.Future[source.InferenceTokensResult] {
 func (pds *PrometheusMetricsQuerier) QueryInferenceCachedTokens(start, end time.Time) *source.Future[source.InferenceTokensResult] {
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
-	
+
 	resultsChan := make(source.QueryResultsChan, 1)
 	resultsChan := make(source.QueryResultsChan, 1)
-	
+
 	go func() {
 	go func() {
 		values, err := queryCounterDelta(ctx, "vllm:prefix_cache_hits_total", start, end)
 		values, err := queryCounterDelta(ctx, "vllm:prefix_cache_hits_total", start, end)
 		if err != nil {
 		if err != nil {
 			resultsChan <- &source.QueryResults{Error: err}
 			resultsChan <- &source.QueryResults{Error: err}
 			return
 			return
 		}
 		}
-		
+
 		results := mapToQueryResults(values)
 		results := mapToQueryResults(values)
 		resultsChan <- &source.QueryResults{Results: results}
 		resultsChan <- &source.QueryResults{Results: results}
 	}()
 	}()
-	
+
 	return source.NewFuture(decodeInferenceTokensResult, resultsChan)
 	return source.NewFuture(decodeInferenceTokensResult, resultsChan)
 }
 }
 
 
 // QueryInferenceCacheConfig implements MetricsQuerier.QueryInferenceCacheConfig
 // QueryInferenceCacheConfig implements MetricsQuerier.QueryInferenceCacheConfig
 func (pds *PrometheusMetricsQuerier) QueryInferenceCacheConfig(t time.Time) *source.Future[source.InferenceCacheConfigResult] {
 func (pds *PrometheusMetricsQuerier) QueryInferenceCacheConfig(t time.Time) *source.Future[source.InferenceCacheConfigResult] {
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
 	ctx := pds.promContexts.NewNamedContext(ClusterContextName)
-	
+
 	resultsChan := make(source.QueryResultsChan, 1)
 	resultsChan := make(source.QueryResultsChan, 1)
-	
+
 	go func() {
 	go func() {
 		configs, err := queryCacheConfigs(ctx, t)
 		configs, err := queryCacheConfigs(ctx, t)
 		if err != nil {
 		if err != nil {
 			resultsChan <- &source.QueryResults{Error: err}
 			resultsChan <- &source.QueryResults{Error: err}
 			return
 			return
 		}
 		}
-		
+
 		results := cacheConfigMapToQueryResults(configs)
 		results := cacheConfigMapToQueryResults(configs)
 		resultsChan <- &source.QueryResults{Results: results}
 		resultsChan <- &source.QueryResults{Results: results}
 	}()
 	}()
-	
+
 	return source.NewFuture(decodeInferenceCacheConfigResult, resultsChan)
 	return source.NewFuture(decodeInferenceCacheConfigResult, resultsChan)
 }
 }
 
 
@@ -138,7 +138,7 @@ func (pds *PrometheusMetricsQuerier) QueryInferenceCacheConfig(t time.Time) *sou
 func decodeInferenceTokensResult(result *source.QueryResult) *source.InferenceTokensResult {
 func decodeInferenceTokensResult(result *source.QueryResult) *source.InferenceTokensResult {
 	key, _ := result.GetString("key")
 	key, _ := result.GetString("key")
 	value := result.Values[0].Value
 	value := result.Values[0].Value
-	
+
 	return &source.InferenceTokensResult{
 	return &source.InferenceTokensResult{
 		Values: map[string]float64{key: value},
 		Values: map[string]float64{key: value},
 	}
 	}
@@ -147,7 +147,7 @@ func decodeInferenceTokensResult(result *source.QueryResult) *source.InferenceTo
 func decodeInferenceProcessingTimeResult(result *source.QueryResult) *source.InferenceProcessingTimeResult {
 func decodeInferenceProcessingTimeResult(result *source.QueryResult) *source.InferenceProcessingTimeResult {
 	key, _ := result.GetString("key")
 	key, _ := result.GetString("key")
 	value := result.Values[0].Value
 	value := result.Values[0].Value
-	
+
 	return &source.InferenceProcessingTimeResult{
 	return &source.InferenceProcessingTimeResult{
 		Values: map[string]float64{key: value},
 		Values: map[string]float64{key: value},
 	}
 	}
@@ -156,7 +156,7 @@ func decodeInferenceProcessingTimeResult(result *source.QueryResult) *source.Inf
 func decodeInferenceCacheConfigResult(result *source.QueryResult) *source.InferenceCacheConfigResult {
 func decodeInferenceCacheConfigResult(result *source.QueryResult) *source.InferenceCacheConfigResult {
 	key, _ := result.GetString("key")
 	key, _ := result.GetString("key")
 	enabled := result.Values[0].Value > 0
 	enabled := result.Values[0].Value > 0
-	
+
 	return &source.InferenceCacheConfigResult{
 	return &source.InferenceCacheConfigResult{
 		Configs: map[string]*source.InferenceCacheConfig{
 		Configs: map[string]*source.InferenceCacheConfig{
 			key: {PrefixCachingEnabled: enabled},
 			key: {PrefixCachingEnabled: enabled},
@@ -316,9 +316,9 @@ func queryCacheConfigs(ctx *Context, t time.Time) (map[string]*source.InferenceC
 		if rawErr == nil {
 		if rawErr == nil {
 			diagResults := NewQueryResults(rawQuery, rawResult, source.ClusterKeyWithDefaults(ctx.config.ClusterLabel))
 			diagResults := NewQueryResults(rawQuery, rawResult, source.ClusterKeyWithDefaults(ctx.config.ClusterLabel))
 			if diagResults.Error == nil && len(diagResults.Results) > 0 {
 			if diagResults.Error == nil && len(diagResults.Results) > 0 {
-				log.Warnf("InferenceCost: vllm:cache_config_info exists in Prometheus but the join with "+
-					"vllm:prompt_tokens_total produced no results — likely a pod-label mismatch between "+
-					"the two metrics (check that both carry matching 'namespace' and 'pod' labels). "+
+				log.Warnf("InferenceCost: vllm:cache_config_info exists in Prometheus but the join with " +
+					"vllm:prompt_tokens_total produced no results — likely a pod-label mismatch between " +
+					"the two metrics (check that both carry matching 'namespace' and 'pod' labels). " +
 					"prefix_caching_off detection will be disabled; allocation method will be 'compute_time'.")
 					"prefix_caching_off detection will be disabled; allocation method will be 'compute_time'.")
 			}
 			}
 		}
 		}

+ 5 - 6
pkg/env/costmodel.go

@@ -104,11 +104,11 @@ const (
 	MetricsEmitterQueryWindowEnvVar = "METRICS_EMITTER_QUERY_WINDOW"
 	MetricsEmitterQueryWindowEnvVar = "METRICS_EMITTER_QUERY_WINDOW"
 
 
 	// Inference Cost
 	// Inference Cost
-	InferenceCostEnabledEnvVar               = "INFERENCE_COST_ENABLED"
-	InferenceModelLabelEnvVar                = "INFERENCE_MODEL_LABEL"
-	InferenceSharedInfraLabelEnvVar          = "INFERENCE_SHARED_INFRA_LABEL"
-	InferenceSharedInfraLabelValueEnvVar     = "INFERENCE_SHARED_INFRA_LABEL_VALUE"
-	InferenceCollectionIntervalEnvVar        = "INFERENCE_COLLECTION_INTERVAL"
+	InferenceCostEnabledEnvVar           = "INFERENCE_COST_ENABLED"
+	InferenceModelLabelEnvVar            = "INFERENCE_MODEL_LABEL"
+	InferenceSharedInfraLabelEnvVar      = "INFERENCE_SHARED_INFRA_LABEL"
+	InferenceSharedInfraLabelValueEnvVar = "INFERENCE_SHARED_INFRA_LABEL_VALUE"
+	InferenceCollectionIntervalEnvVar    = "INFERENCE_COLLECTION_INTERVAL"
 )
 )
 
 
 func GetGCPAuthSecretFilePath() string {
 func GetGCPAuthSecretFilePath() string {
@@ -453,4 +453,3 @@ func GetInferenceSharedInfraLabelValue() string {
 func GetInferenceCollectionInterval() time.Duration {
 func GetInferenceCollectionInterval() time.Duration {
 	return env.GetDuration(InferenceCollectionIntervalEnvVar, 2*time.Minute)
 	return env.GetDuration(InferenceCollectionIntervalEnvVar, 2*time.Minute)
 }
 }
-

+ 3 - 1
pkg/inferencecost/aggregate.go

@@ -224,7 +224,9 @@ type filterSpec struct {
 }
 }
 
 
 // parseFilter parses a Phase-1 filter string of the form
 // parseFilter parses a Phase-1 filter string of the form
-//   prop:"value"[+prop:"value"]*
+//
+//	prop:"value"[+prop:"value"]*
+//
 // All terms are ANDed. Only dimensions in supportedAggregateProperties are
 // All terms are ANDed. Only dimensions in supportedAggregateProperties are
 // accepted. Values are unquoted if surrounded by double-quotes.
 // accepted. Values are unquoted if surrounded by double-quotes.
 //
 //

+ 2 - 3
pkg/inferencecost/aggregate_test.go

@@ -411,7 +411,6 @@ func TestMatchesFilter_NoMatch(t *testing.T) {
 	}
 	}
 }
 }
 
 
-
 func TestMatchesFilter_Pod(t *testing.T) {
 func TestMatchesFilter_Pod(t *testing.T) {
 	ic := &InferenceCostResponse{
 	ic := &InferenceCostResponse{
 		Properties: InferenceCostAPIProperties{
 		Properties: InferenceCostAPIProperties{
@@ -504,13 +503,13 @@ func TestParseFilter_NewDimensions(t *testing.T) {
 	if len(specs) != 3 {
 	if len(specs) != 3 {
 		t.Fatalf("expected 3 specs, got %d", len(specs))
 		t.Fatalf("expected 3 specs, got %d", len(specs))
 	}
 	}
-	
+
 	expectedSpecs := []filterSpec{
 	expectedSpecs := []filterSpec{
 		{property: "pod", value: "llama-pod-123"},
 		{property: "pod", value: "llama-pod-123"},
 		{property: "controller", value: "llama-deployment"},
 		{property: "controller", value: "llama-deployment"},
 		{property: "container", value: "vllm"},
 		{property: "container", value: "vllm"},
 	}
 	}
-	
+
 	for i, expected := range expectedSpecs {
 	for i, expected := range expectedSpecs {
 		if specs[i].property != expected.property || specs[i].value != expected.value {
 		if specs[i].property != expected.property || specs[i].value != expected.value {
 			t.Errorf("spec[%d] = %+v, want %+v", i, specs[i], expected)
 			t.Errorf("spec[%d] = %+v, want %+v", i, specs[i], expected)

+ 5 - 5
pkg/inferencecost/calculator_test.go

@@ -22,11 +22,11 @@ func floatEq(a, b float64) bool { return math.Abs(a-b) < 1e-9 }
 func TestCalculator_BlendedCostPerMillionTokens(t *testing.T) {
 func TestCalculator_BlendedCostPerMillionTokens(t *testing.T) {
 	cfg := defaultConfig()
 	cfg := defaultConfig()
 	m := &InferenceCost{
 	m := &InferenceCost{
-		AllocationTotalCost: 4.0,
-		UsageTotalCost:      1.0,
-		PromptTokens:        800_000,
-		GenerationTokens:    200_000,
-		TotalTokens:         1_000_000,
+		AllocationTotalCost:  4.0,
+		UsageTotalCost:       1.0,
+		PromptTokens:         800_000,
+		GenerationTokens:     200_000,
+		TotalTokens:          1_000_000,
 		EffectiveInputTokens: 800_000,
 		EffectiveInputTokens: 800_000,
 		// no timing data → multiplier fallback
 		// no timing data → multiplier fallback
 	}
 	}

+ 9 - 10
pkg/inferencecost/collector.go

@@ -170,8 +170,8 @@ func (c *Collector) queryAllocationCosts(ctx context.Context, start, end time.Ti
 	for key, result := range results {
 	for key, result := range results {
 		modelName, namespace := parseKey(key)
 		modelName, namespace := parseKey(key)
 		if result.allocationTotalCost > 0 {
 		if result.allocationTotalCost > 0 {
-			log.Debugf("InferenceCost: model=%s ns=%s alloc=$%.4f usage=$%.4f (%.1f%% of alloc)", 
-				modelName, namespace, result.allocationTotalCost, result.usageTotalCost, 
+			log.Debugf("InferenceCost: model=%s ns=%s alloc=$%.4f usage=$%.4f (%.1f%% of alloc)",
+				modelName, namespace, result.allocationTotalCost, result.usageTotalCost,
 				(result.usageTotalCost/result.allocationTotalCost)*100)
 				(result.usageTotalCost/result.allocationTotalCost)*100)
 		}
 		}
 	}
 	}
@@ -263,7 +263,7 @@ func (c *Collector) extractAllocationResults(as *opencost.AllocationSet, isAlloc
 		controller := ""
 		controller := ""
 		controllerKind := ""
 		controllerKind := ""
 		container := ""
 		container := ""
-		
+
 		if alloc.Properties != nil {
 		if alloc.Properties != nil {
 			namespace = alloc.Properties.Namespace
 			namespace = alloc.Properties.Namespace
 			cluster = alloc.Properties.Cluster
 			cluster = alloc.Properties.Cluster
@@ -296,7 +296,7 @@ func (c *Collector) extractAllocationResults(as *opencost.AllocationSet, isAlloc
 			// For usage cost: use TotalCost() from the ShareNone query (no idle)
 			// For usage cost: use TotalCost() from the ShareNone query (no idle)
 			existing.usageTotalCost += alloc.TotalCost()
 			existing.usageTotalCost += alloc.TotalCost()
 		}
 		}
-		
+
 		// When aggregating multiple allocations, preserve the first non-empty values
 		// When aggregating multiple allocations, preserve the first non-empty values
 		// for pod, controller, and container. This provides representative values
 		// for pod, controller, and container. This provides representative values
 		// when costs are aggregated across multiple pods/containers.
 		// when costs are aggregated across multiple pods/containers.
@@ -344,11 +344,11 @@ func canonicalModelName(modelName string) string {
 // namespace.
 // namespace.
 //
 //
 // Two common mismatch examples:
 // Two common mismatch examples:
-//   1. Fully-qualified vLLM model name vs short allocation label:
-//      "google/gemma-4-31B:llm-d-pic" -> "gemma-4-31B:llm-d-pic"
-//   2. Fully-qualified vLLM model name vs short allocation label with a
-//      different vendor/org prefix:
-//      "MiniMaxAI/MiniMax-M2.7:llm-d-pic" -> "MiniMax-M2.7:llm-d-pic"
+//  1. Fully-qualified vLLM model name vs short allocation label:
+//     "google/gemma-4-31B:llm-d-pic" -> "gemma-4-31B:llm-d-pic"
+//  2. Fully-qualified vLLM model name vs short allocation label with a
+//     different vendor/org prefix:
+//     "MiniMaxAI/MiniMax-M2.7:llm-d-pic" -> "MiniMax-M2.7:llm-d-pic"
 //
 //
 // Exact matches are preserved. Keys with no matching allocation-backed target
 // Exact matches are preserved. Keys with no matching allocation-backed target
 // are also preserved unchanged. A warning is logged for every remapped key so
 // are also preserved unchanged. A warning is logged for every remapped key so
@@ -571,7 +571,6 @@ func parseKey(key string) (modelName, namespace string) {
 	return key[:idx], key[idx+1:]
 	return key[:idx], key[idx+1:]
 }
 }
 
 
-
 // mergeTokenResults merges multiple InferenceTokensResult into a single map
 // mergeTokenResults merges multiple InferenceTokensResult into a single map
 func mergeTokenResults(results []*source.InferenceTokensResult) map[string]float64 {
 func mergeTokenResults(results []*source.InferenceTokensResult) map[string]float64 {
 	merged := make(map[string]float64)
 	merged := make(map[string]float64)

+ 8 - 8
pkg/inferencecost/collector_test.go

@@ -22,7 +22,7 @@ func (m *mockQuerier) ComputeAllocation(start, end time.Time) (*opencost.Allocat
 	if m.err != nil {
 	if m.err != nil {
 		return nil, m.err
 		return nil, m.err
 	}
 	}
-	
+
 	// If multiple sets are provided, return them in sequence
 	// If multiple sets are provided, return them in sequence
 	if len(m.sets) > 0 {
 	if len(m.sets) > 0 {
 		if m.callCount < len(m.sets) {
 		if m.callCount < len(m.sets) {
@@ -33,7 +33,7 @@ func (m *mockQuerier) ComputeAllocation(start, end time.Time) (*opencost.Allocat
 		// Return last set for any additional calls
 		// Return last set for any additional calls
 		return m.sets[len(m.sets)-1], nil
 		return m.sets[len(m.sets)-1], nil
 	}
 	}
-	
+
 	// Otherwise return the single set
 	// Otherwise return the single set
 	return m.set, nil
 	return m.set, nil
 }
 }
@@ -48,7 +48,7 @@ func newMockMetricsQuerierWithInferenceMetrics(
 	cacheConfigs map[string]*source.InferenceCacheConfig,
 	cacheConfigs map[string]*source.InferenceCacheConfig,
 ) *source.MockMetricsQuerier {
 ) *source.MockMetricsQuerier {
 	mock := source.NewMockMetricsQuerier()
 	mock := source.NewMockMetricsQuerier()
-	
+
 	// Set up inference metric overrides
 	// Set up inference metric overrides
 	if promptTokens != nil {
 	if promptTokens != nil {
 		mock.SetOverride(source.QueryInferencePromptTokens, []*source.InferenceTokensResult{
 		mock.SetOverride(source.QueryInferencePromptTokens, []*source.InferenceTokensResult{
@@ -80,7 +80,7 @@ func newMockMetricsQuerierWithInferenceMetrics(
 			{Configs: cacheConfigs},
 			{Configs: cacheConfigs},
 		})
 		})
 	}
 	}
-	
+
 	return mock
 	return mock
 }
 }
 
 
@@ -121,7 +121,7 @@ func TestCollector_ExtractAllocationResults(t *testing.T) {
 	now := time.Now()
 	now := time.Now()
 	cfg := baseConfig()
 	cfg := baseConfig()
 	c := &Collector{config: cfg}
 	c := &Collector{config: cfg}
-	
+
 	// Test allocation cost extraction (with idle)
 	// Test allocation cost extraction (with idle)
 	allocWithIdle := &opencost.Allocation{
 	allocWithIdle := &opencost.Allocation{
 		Name:    "llama-3",
 		Name:    "llama-3",
@@ -145,7 +145,7 @@ func TestCollector_ExtractAllocationResults(t *testing.T) {
 	if !ok {
 	if !ok {
 		t.Fatal("expected allocation result for llama-3/llm-prod")
 		t.Fatal("expected allocation result for llama-3/llm-prod")
 	}
 	}
-	
+
 	if !floatEq(r.allocationTotalCost, 4.0) {
 	if !floatEq(r.allocationTotalCost, 4.0) {
 		t.Errorf("allocationTotalCost want 4.0 got %f", r.allocationTotalCost)
 		t.Errorf("allocationTotalCost want 4.0 got %f", r.allocationTotalCost)
 	}
 	}
@@ -175,7 +175,7 @@ func TestCollector_ExtractAllocationResults(t *testing.T) {
 	if !ok {
 	if !ok {
 		t.Fatal("expected usage result for llama-3/llm-prod")
 		t.Fatal("expected usage result for llama-3/llm-prod")
 	}
 	}
-	
+
 	if !floatEq(r2.usageTotalCost, 2.6) {
 	if !floatEq(r2.usageTotalCost, 2.6) {
 		t.Errorf("usageTotalCost want 2.6 got %f", r2.usageTotalCost)
 		t.Errorf("usageTotalCost want 2.6 got %f", r2.usageTotalCost)
 	}
 	}
@@ -396,7 +396,7 @@ func TestCollector_CollectMetrics_EmptyMetrics(t *testing.T) {
 
 
 	now := time.Now()
 	now := time.Now()
 	querier := &mockQuerier{set: opencost.NewAllocationSet(now.Add(-5*time.Minute), now)}
 	querier := &mockQuerier{set: opencost.NewAllocationSet(now.Add(-5*time.Minute), now)}
-	
+
 	// Use the standard mock - it will return empty results by default
 	// Use the standard mock - it will return empty results by default
 	metricsQuerier := source.NewMockMetricsQuerier()
 	metricsQuerier := source.NewMockMetricsQuerier()
 
 

+ 5 - 5
pkg/inferencecost/env.go

@@ -8,8 +8,8 @@ import (
 )
 )
 
 
 func isInferenceCostEnabled() bool         { return env.IsInferenceCostEnabled() }
 func isInferenceCostEnabled() bool         { return env.IsInferenceCostEnabled() }
-func getPrometheusURL() string              { return coreenv.Get("PROMETHEUS_SERVER_ENDPOINT", "") }
-func getModelLabel() string                 { return env.GetInferenceModelLabel() }
-func getSharedInfraLabel() string           { return env.GetInferenceSharedInfraLabel() }
-func getSharedInfraLabelValue() string      { return env.GetInferenceSharedInfraLabelValue() }
-func getCollectionInterval() time.Duration  { return env.GetInferenceCollectionInterval() }
+func getPrometheusURL() string             { return coreenv.Get("PROMETHEUS_SERVER_ENDPOINT", "") }
+func getModelLabel() string                { return env.GetInferenceModelLabel() }
+func getSharedInfraLabel() string          { return env.GetInferenceSharedInfraLabel() }
+func getSharedInfraLabelValue() string     { return env.GetInferenceSharedInfraLabelValue() }
+func getCollectionInterval() time.Duration { return env.GetInferenceCollectionInterval() }

+ 5 - 5
pkg/inferencecost/exporter_test.go

@@ -35,12 +35,12 @@ func sampleMetric(method AllocationMethod) *InferenceCost {
 			ModelVersion: "v1",
 			ModelVersion: "v1",
 			Namespace:    "llm-prod",
 			Namespace:    "llm-prod",
 		},
 		},
-		AllocationTotalCost: 4.0,
-		UsageTotalCost:      1.0,
-		TotalTokens:         1_000_000,
+		AllocationTotalCost:  4.0,
+		UsageTotalCost:       1.0,
+		TotalTokens:          1_000_000,
 		EffectiveInputTokens: 800_000,
 		EffectiveInputTokens: 800_000,
-		GenerationTokens:    200_000,
-		AllocationMethod:    method,
+		GenerationTokens:     200_000,
+		AllocationMethod:     method,
 		CostPerMillionTokens: map[CostBasis]float64{
 		CostPerMillionTokens: map[CostBasis]float64{
 			CostBasisAllocation: 4.0,
 			CostBasisAllocation: 4.0,
 			CostBasisUsage:      1.0,
 			CostBasisUsage:      1.0,

+ 6 - 6
pkg/inferencecost/queryservice_helper.go

@@ -11,13 +11,13 @@ import (
 
 
 // QueryRequest holds the parsed parameters for an inference cost query.
 // QueryRequest holds the parsed parameters for an inference cost query.
 type QueryRequest struct {
 type QueryRequest struct {
-	Start      time.Time
-	End        time.Time
-	CostBasis  CostBasis
+	Start       time.Time
+	End         time.Time
+	CostBasis   CostBasis
 	AggregateBy []string
 	AggregateBy []string
-	Accumulate opencost.AccumulateOption
-	Filter     []filterSpec
-	Step       time.Duration
+	Accumulate  opencost.AccumulateOption
+	Filter      []filterSpec
+	Step        time.Duration
 }
 }
 
 
 // ParseInferenceCostRequest parses the common query parameters from an HTTP
 // ParseInferenceCostRequest parses the common query parameters from an HTTP

+ 0 - 1
pkg/inferencecost/types.go

@@ -145,7 +145,6 @@ type Config struct {
 	// OutputTokenCostMultiplier is the output/input cost ratio used when
 	// OutputTokenCostMultiplier is the output/input cost ratio used when
 	// AllocationMode is "multiplier".
 	// AllocationMode is "multiplier".
 	OutputTokenCostMultiplier float64
 	OutputTokenCostMultiplier float64
-
 }
 }
 
 
 const (
 const (