@@ -219,6 +219,123 @@ func configureDestinationRule(log logr.Logger, resource *unstructured.Unstructur
219219 resource .SetNamespace (gatewayNamespace )
220220}
221221
222+ // configureTelemetryPolicy is a post-render action that creates a TelemetryPolicy
223+ // resource based on the ModelsAsService telemetry configuration.
224+ //
225+ // The TelemetryPolicy is generated programmatically (not from manifests) because
226+ // its content is entirely dynamic based on the spec.telemetry.metrics configuration.
227+ func configureTelemetryPolicy (ctx context.Context , rr * types.ReconciliationRequest ) error {
228+ log := logf .FromContext (ctx )
229+
230+ maas , ok := rr .Instance .(* componentApi.ModelsAsService )
231+ if ! ok {
232+ return fmt .Errorf ("resource instance %v is not a componentApi.ModelsAsService" , rr .Instance )
233+ }
234+
235+ gatewayNamespace := maas .Spec .GatewayRef .Namespace
236+ gatewayName := maas .Spec .GatewayRef .Name
237+
238+ // Build the labels map based on telemetry configuration
239+ metricLabels := buildTelemetryLabels (log , maas .Spec .Telemetry )
240+
241+ // Create the TelemetryPolicy resource
242+ telemetryPolicy := & unstructured.Unstructured {
243+ Object : map [string ]interface {}{
244+ "apiVersion" : "extensions.kuadrant.io/v1alpha1" ,
245+ "kind" : "TelemetryPolicy" ,
246+ "metadata" : map [string ]interface {}{
247+ "name" : TelemetryPolicyName ,
248+ "namespace" : gatewayNamespace ,
249+ "labels" : map [string ]interface {}{
250+ "app.kubernetes.io/part-of" : "maas-observability" ,
251+ },
252+ },
253+ "spec" : map [string ]interface {}{
254+ "targetRef" : map [string ]interface {}{
255+ "group" : "gateway.networking.k8s.io" ,
256+ "kind" : "Gateway" ,
257+ "name" : gatewayName ,
258+ },
259+ "metrics" : map [string ]interface {}{
260+ "default" : map [string ]interface {}{
261+ "labels" : metricLabels ,
262+ },
263+ },
264+ },
265+ },
266+ }
267+
268+ log .V (2 ).Info ("Creating TelemetryPolicy" ,
269+ "name" , TelemetryPolicyName ,
270+ "namespace" , gatewayNamespace ,
271+ "targetGateway" , gatewayName ,
272+ "labels" , metricLabels )
273+
274+ // Add to resources for deployment
275+ rr .Resources = append (rr .Resources , * telemetryPolicy )
276+
277+ return nil
278+ }
279+
280+ // buildTelemetryLabels creates the metric labels map based on the telemetry configuration.
281+ // It includes always-on dimensions and configurable dimensions based on MetricsConfig settings.
282+ func buildTelemetryLabels (log logr.Logger , config * componentApi.TelemetryConfig ) map [string ]interface {} {
283+ // Default values when config is nil or metrics is nil
284+ captureOrganization := true
285+ captureUser := true
286+ captureGroup := false
287+ captureModelUsage := true
288+
289+ if config != nil && config .Metrics != nil {
290+ metrics := config .Metrics
291+ if metrics .CaptureOrganization != nil {
292+ captureOrganization = * metrics .CaptureOrganization
293+ }
294+ if metrics .CaptureUser != nil {
295+ captureUser = * metrics .CaptureUser
296+ }
297+ if metrics .CaptureGroup != nil {
298+ captureGroup = * metrics .CaptureGroup
299+ }
300+ if metrics .CaptureModelUsage != nil {
301+ captureModelUsage = * metrics .CaptureModelUsage
302+ }
303+ }
304+
305+ // Always-on dimensions - essential for billing and access control
306+ labels := map [string ]interface {}{
307+ "subscription" : "auth.identity.selected_subscription" ,
308+ "cost_center" : "auth.identity.costCenter" ,
309+ "tier" : "auth.identity.tier" ,
310+ }
311+
312+ // Configurable dimensions
313+ if captureOrganization {
314+ labels ["organization_id" ] = "auth.identity.organizationId"
315+ }
316+
317+ if captureUser {
318+ labels ["user" ] = "auth.identity.userid"
319+ }
320+
321+ if captureGroup {
322+ labels ["group" ] = "auth.identity.group"
323+ }
324+
325+ if captureModelUsage {
326+ labels ["model" ] = "responseBodyJSON(\" /model\" )"
327+ }
328+
329+ log .V (4 ).Info ("Built telemetry labels" ,
330+ "captureOrganization" , captureOrganization ,
331+ "captureUser" , captureUser ,
332+ "captureGroup" , captureGroup ,
333+ "captureModelUsage" , captureModelUsage ,
334+ "totalLabels" , len (labels ))
335+
336+ return labels
337+ }
338+
222339// configureConfigHashAnnotation adds a hash annotation to the maas-api Deployment
223340// to trigger rolling restarts when the ConfigMap changes.
224341// This is necessary because env vars sourced via valueFrom.configMapKeyRef
0 commit comments