You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by gi...@apache.org on 2026/08/14 11:12:48 UTC

(dubbo-kubernetes) branch master updated: Refactoring for observability (#1018)

This is an automated email from the ASF dual-hosted git repository.

github-actions[bot] pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git


The following commit(s) were added to refs/heads/master by this push:
     new 04a44213 Refactoring for observability (#1018)
04a44213 is described below

commit 04a442135aa558c89c8307c44d28430ac56fdec0
Author: mfordjody <11...@qq.com>
AuthorDate: Fri Aug 14 19:12:42 2026 +0800

    Refactoring for observability (#1018)
---
 .../pkg/bootstrap/inherent_grpc_controller.go      | 98 ++++++++++++++++++----
 .../pkg/bootstrap/inherent_grpc_controller_test.go | 64 +++++++++++++-
 .../pkg/config/kube/crd/conversion_test.go         |  2 +-
 .../pkg/config/kube/crdclient/types.gen.go         | 28 +++----
 .../config/kube/gateway/deployment_controller.go   |  2 +-
 .../kube/gateway/deployment_controller_test.go     |  4 +-
 go.mod                                             |  8 +-
 go.sum                                             |  8 +-
 manifests/charts/base/files/crd-all.gen.yaml       | 74 ++++++++++++++--
 .../schema/codegen/templates/clients.go.tmpl       |  2 +-
 .../schema/codegen/templates/crdclient.go.tmpl     |  2 +-
 pkg/config/schema/codegen/templates/types.go.tmpl  |  2 +-
 pkg/config/schema/collections/collections.gen.go   | 10 +--
 pkg/config/schema/gvk/resources.gen.go             |  2 +-
 pkg/config/schema/gvr/resources.gen.go             |  2 +-
 pkg/config/schema/kubeclient/resources.gen.go      | 16 ++--
 pkg/config/schema/kubetypes/resources.gen.go       |  8 +-
 pkg/config/schema/metadata.yaml                    |  6 +-
 pkg/config/telemetry/telemetry.go                  | 79 ++++++++++++++++-
 pkg/config/telemetry/telemetry_test.go             | 76 ++++++++++++++++-
 pkg/config/validation/validators.go                | 55 +++++++++++-
 pkg/config/validation/validators_test.go           | 56 ++++++++++++-
 pkg/webhooks/server/server.go                      |  2 +-
 pkg/webhooks/server/server_test.go                 |  2 +-
 samples/addons/telemetry.yaml                      | 47 +++--------
 25 files changed, 538 insertions(+), 117 deletions(-)

diff --git a/dubbod/discovery/pkg/bootstrap/inherent_grpc_controller.go b/dubbod/discovery/pkg/bootstrap/inherent_grpc_controller.go
index aa0970ba..64e2b814 100644
--- a/dubbod/discovery/pkg/bootstrap/inherent_grpc_controller.go
+++ b/dubbod/discovery/pkg/bootstrap/inherent_grpc_controller.go
@@ -31,7 +31,9 @@ import (
 	"github.com/apache/dubbo-kubernetes/pkg/config/constants"
 	configlabels "github.com/apache/dubbo-kubernetes/pkg/config/labels"
 	meshconfig "github.com/apache/dubbo-kubernetes/pkg/config/mesh"
+	"github.com/apache/dubbo-kubernetes/pkg/config/schema/gvk"
 	"github.com/apache/dubbo-kubernetes/pkg/config/schema/kind"
+	telemetryconfig "github.com/apache/dubbo-kubernetes/pkg/config/telemetry"
 	"github.com/apache/dubbo-kubernetes/pkg/grpcxds"
 	kubelib "github.com/apache/dubbo-kubernetes/pkg/kube"
 	"github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
@@ -239,7 +241,7 @@ func inherentGRPCRuntimeConfigNeedsUpdate(req *discoverymodel.PushRequest) bool
 	}
 	for cfg := range req.ConfigsUpdated {
 		switch cfg.Kind {
-		case kind.HTTPRoute, kind.BackendTLSPolicy, kind.CircuitBreakerPolicy, kind.FaultInjectionPolicy, kind.PeerAuthentication, kind.RequestAuthentication, kind.AuthorizationPolicy, kind.Service, kind.EndpointSlice, kind.Endpoints, kind.Pod, kind.Namespace:
+		case kind.HTTPRoute, kind.BackendTLSPolicy, kind.CircuitBreakerPolicy, kind.FaultInjectionPolicy, kind.PeerAuthentication, kind.RequestAuthentication, kind.AuthorizationPolicy, kind.Telemetry, kind.Service, kind.EndpointSlice, kind.Endpoints, kind.Pod, kind.Namespace:
 			return true
 		}
 	}
@@ -357,15 +359,36 @@ type inherentGRPCWorkloadContext struct {
 }
 
 type inherentGRPCRuntimeConfig struct {
-	Version      string                             `json:"version"`
-	Mode         string                             `json:"mode"`
-	Env          map[string]string                  `json:"env"`
-	Bootstrap    inherentGRPCBootstrapRuntimeConfig `json:"bootstrap"`
-	Certificates inherentGRPCCertRuntimeConfig      `json:"certificates"`
-	Keepalive    inherentGRPCKeepaliveRuntimeConfig `json:"keepalive"`
-	Workload     inherentGRPCWorkloadRuntimeConfig  `json:"workload"`
-	Services     []inherentGRPCServiceRuntimeConfig `json:"services,omitempty"`
-	Routes       []inherentGRPCRouteRuntimeConfig   `json:"routes,omitempty"`
+	Version      string                              `json:"version"`
+	Mode         string                              `json:"mode"`
+	Env          map[string]string                   `json:"env"`
+	Bootstrap    inherentGRPCBootstrapRuntimeConfig  `json:"bootstrap"`
+	Certificates inherentGRPCCertRuntimeConfig       `json:"certificates"`
+	Keepalive    inherentGRPCKeepaliveRuntimeConfig  `json:"keepalive"`
+	Workload     inherentGRPCWorkloadRuntimeConfig   `json:"workload"`
+	Telemetry    *inherentGRPCTelemetryRuntimeConfig `json:"telemetry,omitempty"`
+	Services     []inherentGRPCServiceRuntimeConfig  `json:"services,omitempty"`
+	Routes       []inherentGRPCRouteRuntimeConfig    `json:"routes,omitempty"`
+}
+
+type inherentGRPCTelemetryRuntimeConfig struct {
+	Metrics *inherentGRPCMetricsRuntimeConfig `json:"metrics,omitempty"`
+}
+
+type inherentGRPCMetricsRuntimeConfig struct {
+	Enabled   bool                                  `json:"enabled"`
+	Providers []string                              `json:"providers,omitempty"`
+	Rules     []inherentGRPCMetricRuleRuntimeConfig `json:"rules,omitempty"`
+}
+
+type inherentGRPCMetricRuleRuntimeConfig struct {
+	Metric string                                          `json:"metric"`
+	Scope  string                                          `json:"scope"`
+	Tags   map[string]inherentGRPCTagOverrideRuntimeConfig `json:"tags,omitempty"`
+}
+
+type inherentGRPCTagOverrideRuntimeConfig struct {
+	Action string `json:"action"`
 }
 
 type inherentGRPCBootstrapRuntimeConfig struct {
@@ -479,7 +502,7 @@ func (c *inherentGRPCWorkloadController) buildSecret(pod *corev1.Pod, current *c
 	}
 
 	services, routes := c.buildRuntimeTrafficConfig()
-	runtimeConfigJSON, err := buildRuntimeConfigJSON(workload, services, routes)
+	runtimeConfigJSON, err := buildRuntimeConfigJSON(workload, services, routes, c.resolveTelemetry(pod))
 	if err != nil {
 		return nil, time.Time{}, err
 	}
@@ -496,6 +519,22 @@ func (c *inherentGRPCWorkloadController) buildSecret(pod *corev1.Pod, current *c
 	return secret, expireAt, nil
 }
 
+func (c *inherentGRPCWorkloadController) resolveTelemetry(pod *corev1.Pod) telemetryconfig.EffectiveTracing {
+	if c == nil || c.server == nil || c.server.environment == nil || c.server.environment.ConfigStore == nil || pod == nil {
+		return telemetryconfig.EffectiveTracing{}
+	}
+	meshNamespace := c.server.namespace
+	if meshNamespace == "" {
+		meshNamespace = constants.DubboSystemNamespace
+	}
+	return telemetryconfig.Resolve(
+		telemetryconfig.ResourcesFromConfigs(c.server.environment.List(gvk.Telemetry, "")),
+		meshNamespace,
+		pod.Namespace,
+		pod.Labels,
+	)
+}
+
 func buildInherentGRPCSecret(pod *corev1.Pod, bootstrapJSON, runtimeConfigJSON, certChain, keyPEM, rootCert []byte) *corev1.Secret {
 	return &corev1.Secret{
 		ObjectMeta: metav1.ObjectMeta{
@@ -666,7 +705,12 @@ func buildBootstrapJSON(workload *inherentGRPCWorkloadContext) ([]byte, error) {
 	return json.MarshalIndent(bootstrapCfg, "", "  ")
 }
 
-func buildRuntimeConfigJSON(workload *inherentGRPCWorkloadContext, services []inherentGRPCServiceRuntimeConfig, routes []inherentGRPCRouteRuntimeConfig) ([]byte, error) {
+func buildRuntimeConfigJSON(
+	workload *inherentGRPCWorkloadContext,
+	services []inherentGRPCServiceRuntimeConfig,
+	routes []inherentGRPCRouteRuntimeConfig,
+	effectiveTelemetry telemetryconfig.EffectiveTracing,
+) ([]byte, error) {
 	cfg := inherentGRPCRuntimeConfig{
 		Version: inherentGRPCRuntimeConfigVersion,
 		Mode:    "inherent-grpc",
@@ -719,12 +763,38 @@ func buildRuntimeConfigJSON(workload *inherentGRPCWorkloadContext, services []in
 			TrustDomain:    workload.trustDomain,
 			ClusterID:      workload.clusterID,
 		},
-		Services: services,
-		Routes:   routes,
+		Telemetry: inherentGRPCTelemetryConfig(effectiveTelemetry),
+		Services:  services,
+		Routes:    routes,
 	}
 	return json.MarshalIndent(cfg, "", "  ")
 }
 
+func inherentGRPCTelemetryConfig(effective telemetryconfig.EffectiveTracing) *inherentGRPCTelemetryRuntimeConfig {
+	if !effective.MetricsConfigured {
+		return nil
+	}
+	metrics := &inherentGRPCMetricsRuntimeConfig{
+		Enabled:   effective.MetricsEnabled(),
+		Providers: append([]string(nil), effective.MetricProviders...),
+		Rules:     make([]inherentGRPCMetricRuleRuntimeConfig, 0, len(effective.MetricRules)),
+	}
+	for _, rule := range effective.MetricRules {
+		runtimeRule := inherentGRPCMetricRuleRuntimeConfig{
+			Metric: rule.Metric.String(),
+			Scope:  rule.Scope.String(),
+		}
+		if len(rule.Tags) > 0 {
+			runtimeRule.Tags = make(map[string]inherentGRPCTagOverrideRuntimeConfig, len(rule.Tags))
+			for _, tag := range rule.Tags {
+				runtimeRule.Tags[tag.Name] = inherentGRPCTagOverrideRuntimeConfig{Action: tag.Action.String()}
+			}
+		}
+		metrics.Rules = append(metrics.Rules, runtimeRule)
+	}
+	return &inherentGRPCTelemetryRuntimeConfig{Metrics: metrics}
+}
+
 func (c *inherentGRPCWorkloadController) buildRuntimeTrafficConfig() ([]inherentGRPCServiceRuntimeConfig, []inherentGRPCRouteRuntimeConfig) {
 	if c.server == nil || c.server.environment == nil {
 		return nil, nil
diff --git a/dubbod/discovery/pkg/bootstrap/inherent_grpc_controller_test.go b/dubbod/discovery/pkg/bootstrap/inherent_grpc_controller_test.go
index b3c994e5..164e6ebe 100644
--- a/dubbod/discovery/pkg/bootstrap/inherent_grpc_controller_test.go
+++ b/dubbod/discovery/pkg/bootstrap/inherent_grpc_controller_test.go
@@ -31,6 +31,7 @@ import (
 	"github.com/apache/dubbo-kubernetes/pkg/config/schema/collections"
 	"github.com/apache/dubbo-kubernetes/pkg/config/schema/gvk"
 	"github.com/apache/dubbo-kubernetes/pkg/config/schema/kind"
+	telemetryconfig "github.com/apache/dubbo-kubernetes/pkg/config/telemetry"
 	"github.com/apache/dubbo-kubernetes/pkg/grpcxds"
 	"github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
 	"github.com/apache/dubbo-kubernetes/pkg/kube/inject"
@@ -38,6 +39,7 @@ import (
 	"github.com/apache/dubbo-kubernetes/pkg/util/sets"
 	networking "github.com/kdubbo/api/networking/v1alpha3"
 	security "github.com/kdubbo/api/security/v1alpha3"
+	telemetryapi "github.com/kdubbo/api/telemetry/v1alpha3"
 	"google.golang.org/protobuf/types/known/durationpb"
 	"google.golang.org/protobuf/types/known/wrapperspb"
 	corev1 "k8s.io/api/core/v1"
@@ -149,7 +151,19 @@ func TestBuildRuntimeConfigJSON(t *testing.T) {
 		caAddress:        "192.168.15.164:32049",
 	}
 
-	data, err := buildRuntimeConfigJSON(workload, nil, nil)
+	effectiveTelemetry := telemetryconfig.EffectiveTracing{
+		MetricsConfigured: true,
+		MetricProviders:   []string{telemetryconfig.PrometheusProvider},
+		MetricRules: []telemetryconfig.MetricRule{{
+			Metric: telemetryapi.StandardMetric_REQUEST_COUNT,
+			Scope:  telemetryapi.MetricScope_CLIENT_AND_SERVER,
+			Tags: []telemetryconfig.MetricTagOverride{{
+				Name:   "grpc_response_status",
+				Action: telemetryapi.TagOverride_REMOVE,
+			}},
+		}},
+	}
+	data, err := buildRuntimeConfigJSON(workload, nil, nil, effectiveTelemetry)
 	if err != nil {
 		t.Fatalf("buildRuntimeConfigJSON() failed: %v", err)
 	}
@@ -222,6 +236,54 @@ func TestBuildRuntimeConfigJSON(t *testing.T) {
 	if got.Workload.ClusterID != workload.clusterID {
 		t.Fatalf("clusterId = %q, want %q", got.Workload.ClusterID, workload.clusterID)
 	}
+	if got.Telemetry == nil || got.Telemetry.Metrics == nil || !got.Telemetry.Metrics.Enabled {
+		t.Fatalf("telemetry metrics = %#v, want enabled", got.Telemetry)
+	}
+	if len(got.Telemetry.Metrics.Rules) != 1 {
+		t.Fatalf("telemetry rules = %#v, want one", got.Telemetry.Metrics.Rules)
+	}
+	rule := got.Telemetry.Metrics.Rules[0]
+	if rule.Metric != "REQUEST_COUNT" || rule.Scope != "CLIENT_AND_SERVER" {
+		t.Fatalf("telemetry rule = %#v", rule)
+	}
+	if tag := rule.Tags["grpc_response_status"]; tag.Action != "REMOVE" {
+		t.Fatalf("grpc_response_status override = %#v", tag)
+	}
+}
+
+func TestResolveInherentTelemetryForWorkload(t *testing.T) {
+	env, _ := newInherentRuntimeTestEnvironment(t, []config.Config{{
+		Meta: config.Meta{
+			GroupVersionKind: gvk.Telemetry,
+			Name:             "metrics-tags",
+			Namespace:        constants.DubboSystemNamespace,
+		},
+		Spec: &telemetryapi.Telemetry{Metrics: []*telemetryapi.Metrics{{
+			Providers: []*telemetryapi.Metrics_MetricsProvider{{Name: telemetryconfig.PrometheusProvider}},
+			Rules: []*telemetryapi.MetricRule{{
+				Metric: telemetryapi.StandardMetric_REQUEST_COUNT,
+				Scope:  telemetryapi.MetricScope_CLIENT_AND_SERVER,
+				Tags: map[string]*telemetryapi.TagOverride{
+					"grpc_response_status": {Action: telemetryapi.TagOverride_REMOVE},
+				},
+			}},
+		}}},
+	}}, nil)
+	controller := &inherentGRPCWorkloadController{server: &Server{
+		environment: env,
+		namespace:   constants.DubboSystemNamespace,
+	}}
+
+	got := controller.resolveTelemetry(&corev1.Pod{ObjectMeta: metav1.ObjectMeta{
+		Namespace: "app",
+		Labels:    map[string]string{"app": "frontend"},
+	}})
+	if !got.MetricsEnabled() || len(got.MetricRules) != 1 {
+		t.Fatalf("resolved telemetry = %#v", got)
+	}
+	if got.MetricRules[0].Scope != telemetryapi.MetricScope_CLIENT_AND_SERVER {
+		t.Fatalf("scope = %s, want CLIENT_AND_SERVER", got.MetricRules[0].Scope)
+	}
 }
 
 func TestBuildWorkloadContextUsesInjectedRemoteValues(t *testing.T) {
diff --git a/dubbod/discovery/pkg/config/kube/crd/conversion_test.go b/dubbod/discovery/pkg/config/kube/crd/conversion_test.go
index fe45627a..59321b14 100644
--- a/dubbod/discovery/pkg/config/kube/crd/conversion_test.go
+++ b/dubbod/discovery/pkg/config/kube/crd/conversion_test.go
@@ -19,7 +19,7 @@ import (
 	"testing"
 
 	"github.com/apache/dubbo-kubernetes/pkg/config/schema/collections"
-	telemetry "github.com/kdubbo/api/telemetry/v1alpha1"
+	telemetry "github.com/kdubbo/api/telemetry/v1alpha3"
 )
 
 func TestFromJSONTelemetryScalarWrappers(t *testing.T) {
diff --git a/dubbod/discovery/pkg/config/kube/crdclient/types.gen.go b/dubbod/discovery/pkg/config/kube/crdclient/types.gen.go
index 731cc4db..67eb7da9 100755
--- a/dubbod/discovery/pkg/config/kube/crdclient/types.gen.go
+++ b/dubbod/discovery/pkg/config/kube/crdclient/types.gen.go
@@ -17,10 +17,10 @@ import (
 	githubcomkdubboapimetav1alpha1 "github.com/kdubbo/api/meta/v1alpha1"
 	githubcomkdubboapinetworkingv1alpha3 "github.com/kdubbo/api/networking/v1alpha3"
 	githubcomkdubboapisecurityv1alpha3 "github.com/kdubbo/api/security/v1alpha3"
-	githubcomkdubboapitelemetryv1alpha1 "github.com/kdubbo/api/telemetry/v1alpha1"
+	githubcomkdubboapitelemetryv1alpha3 "github.com/kdubbo/api/telemetry/v1alpha3"
 	apigithubcomapachedubbokubernetesapinetworkingv1alpha3 "github.com/kdubbo/client-go/pkg/apis/networking/v1alpha3"
 	apigithubcomapachedubbokubernetesapisecurityv1alpha3 "github.com/kdubbo/client-go/pkg/apis/security/v1alpha3"
-	apigithubcomapachedubbokubernetesapitelemetryv1alpha1 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha1"
+	apigithubcomapachedubbokubernetesapitelemetryv1alpha3 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha3"
 	k8sioapiadmissionregistrationv1 "k8s.io/api/admissionregistration/v1"
 	k8sioapiappsv1 "k8s.io/api/apps/v1"
 	k8sioapiautoscalingv2 "k8s.io/api/autoscaling/v2"
@@ -101,9 +101,9 @@ func create(c kube.Client, cfg config.Config, objMeta metav1.ObjectMeta) (metav1
 			Spec:       *(cfg.Spec.(*githubcomkdubboapinetworkingv1alpha3.ServiceEntry)),
 		}, metav1.CreateOptions{})
 	case gvk.Telemetry:
-		return c.Dubbo().TelemetryV1alpha1().Telemetries(cfg.Namespace).Create(context.TODO(), &apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry{
+		return c.Dubbo().TelemetryV1alpha3().Telemetries(cfg.Namespace).Create(context.TODO(), &apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry{
 			ObjectMeta: objMeta,
-			Spec:       *(cfg.Spec.(*githubcomkdubboapitelemetryv1alpha1.Telemetry)),
+			Spec:       *(cfg.Spec.(*githubcomkdubboapitelemetryv1alpha3.Telemetry)),
 		}, metav1.CreateOptions{})
 	case gvk.WorkloadEntry:
 		return c.Dubbo().NetworkingV1alpha3().WorkloadEntries(cfg.Namespace).Create(context.TODO(), &apigithubcomapachedubbokubernetesapinetworkingv1alpha3.WorkloadEntry{
@@ -183,9 +183,9 @@ func update(c kube.Client, cfg config.Config, objMeta metav1.ObjectMeta) (metav1
 			Spec:       *(cfg.Spec.(*githubcomkdubboapinetworkingv1alpha3.ServiceEntry)),
 		}, metav1.UpdateOptions{})
 	case gvk.Telemetry:
-		return c.Dubbo().TelemetryV1alpha1().Telemetries(cfg.Namespace).Update(context.TODO(), &apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry{
+		return c.Dubbo().TelemetryV1alpha3().Telemetries(cfg.Namespace).Update(context.TODO(), &apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry{
 			ObjectMeta: objMeta,
-			Spec:       *(cfg.Spec.(*githubcomkdubboapitelemetryv1alpha1.Telemetry)),
+			Spec:       *(cfg.Spec.(*githubcomkdubboapitelemetryv1alpha3.Telemetry)),
 		}, metav1.UpdateOptions{})
 	case gvk.WorkloadEntry:
 		return c.Dubbo().NetworkingV1alpha3().WorkloadEntries(cfg.Namespace).Update(context.TODO(), &apigithubcomapachedubbokubernetesapinetworkingv1alpha3.WorkloadEntry{
@@ -260,7 +260,7 @@ func updateStatus(c kube.Client, cfg config.Config, objMeta metav1.ObjectMeta) (
 			Status:     *(cfg.Status.(*githubcomkdubboapimetav1alpha1.DubboStatus)),
 		}, metav1.UpdateOptions{})
 	case gvk.Telemetry:
-		return c.Dubbo().TelemetryV1alpha1().Telemetries(cfg.Namespace).UpdateStatus(context.TODO(), &apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry{
+		return c.Dubbo().TelemetryV1alpha3().Telemetries(cfg.Namespace).UpdateStatus(context.TODO(), &apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry{
 			ObjectMeta: objMeta,
 			Status:     *(cfg.Status.(*githubcomkdubboapimetav1alpha1.DubboStatus)),
 		}, metav1.UpdateOptions{})
@@ -475,19 +475,19 @@ func patch(c kube.Client, orig config.Config, origMeta metav1.ObjectMeta, mod co
 		return c.Dubbo().NetworkingV1alpha3().ServiceEntries(orig.Namespace).
 			Patch(context.TODO(), orig.Name, typ, patchBytes, metav1.PatchOptions{FieldManager: "pilot-discovery"})
 	case gvk.Telemetry:
-		oldRes := &apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry{
+		oldRes := &apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry{
 			ObjectMeta: origMeta,
-			Spec:       *(orig.Spec.(*githubcomkdubboapitelemetryv1alpha1.Telemetry)),
+			Spec:       *(orig.Spec.(*githubcomkdubboapitelemetryv1alpha3.Telemetry)),
 		}
-		modRes := &apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry{
+		modRes := &apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry{
 			ObjectMeta: modMeta,
-			Spec:       *(mod.Spec.(*githubcomkdubboapitelemetryv1alpha1.Telemetry)),
+			Spec:       *(mod.Spec.(*githubcomkdubboapitelemetryv1alpha3.Telemetry)),
 		}
 		patchBytes, err := genPatchBytes(oldRes, modRes, typ)
 		if err != nil {
 			return nil, err
 		}
-		return c.Dubbo().TelemetryV1alpha1().Telemetries(orig.Namespace).
+		return c.Dubbo().TelemetryV1alpha3().Telemetries(orig.Namespace).
 			Patch(context.TODO(), orig.Name, typ, patchBytes, metav1.PatchOptions{FieldManager: "pilot-discovery"})
 	case gvk.WorkloadEntry:
 		oldRes := &apigithubcomapachedubbokubernetesapinetworkingv1alpha3.WorkloadEntry{
@@ -542,7 +542,7 @@ func delete(c kube.Client, typ config.GroupVersionKind, name, namespace string,
 	case gvk.ServiceEntry:
 		return c.Dubbo().NetworkingV1alpha3().ServiceEntries(namespace).Delete(context.TODO(), name, deleteOptions)
 	case gvk.Telemetry:
-		return c.Dubbo().TelemetryV1alpha1().Telemetries(namespace).Delete(context.TODO(), name, deleteOptions)
+		return c.Dubbo().TelemetryV1alpha3().Telemetries(namespace).Delete(context.TODO(), name, deleteOptions)
 	case gvk.WorkloadEntry:
 		return c.Dubbo().NetworkingV1alpha3().WorkloadEntries(namespace).Delete(context.TODO(), name, deleteOptions)
 	default:
@@ -1107,7 +1107,7 @@ var translationMap = map[config.GroupVersionKind]func(r runtime.Object) config.C
 		}
 	},
 	gvk.Telemetry: func(r runtime.Object) config.Config {
-		obj := r.(*apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry)
+		obj := r.(*apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry)
 		return config.Config{
 			Meta: config.Meta{
 				GroupVersionKind:  gvk.Telemetry,
diff --git a/dubbod/discovery/pkg/config/kube/gateway/deployment_controller.go b/dubbod/discovery/pkg/config/kube/gateway/deployment_controller.go
index 8ce60041..6e4ccd28 100644
--- a/dubbod/discovery/pkg/config/kube/gateway/deployment_controller.go
+++ b/dubbod/discovery/pkg/config/kube/gateway/deployment_controller.go
@@ -55,7 +55,7 @@ import (
 	dubbolog "github.com/apache/dubbo-kubernetes/pkg/log"
 	networking "github.com/kdubbo/api/networking/v1alpha3"
 	clientnetworking "github.com/kdubbo/client-go/pkg/apis/networking/v1alpha3"
-	clienttelemetry "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha1"
+	clienttelemetry "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha3"
 	"google.golang.org/protobuf/types/known/durationpb"
 	"google.golang.org/protobuf/types/known/wrapperspb"
 )
diff --git a/dubbod/discovery/pkg/config/kube/gateway/deployment_controller_test.go b/dubbod/discovery/pkg/config/kube/gateway/deployment_controller_test.go
index 05784f99..a3fbcd87 100644
--- a/dubbod/discovery/pkg/config/kube/gateway/deployment_controller_test.go
+++ b/dubbod/discovery/pkg/config/kube/gateway/deployment_controller_test.go
@@ -30,7 +30,7 @@ import (
 	"github.com/apache/dubbo-kubernetes/pkg/kube/inject"
 	"github.com/google/go-cmp/cmp"
 	networking "github.com/kdubbo/api/networking/v1alpha3"
-	apitelemetry "github.com/kdubbo/api/telemetry/v1alpha1"
+	apitelemetry "github.com/kdubbo/api/telemetry/v1alpha3"
 	typeapi "github.com/kdubbo/api/type/v1alpha3"
 	"google.golang.org/protobuf/types/known/durationpb"
 	"google.golang.org/protobuf/types/known/wrapperspb"
@@ -768,6 +768,7 @@ func TestKubeGatewayTemplateRendersDxgateResources(t *testing.T) {
 		!strings.Contains(rendered[4], `value: "http://tracing.dubbo-system.svc:4317"`) {
 		t.Fatalf("deployment did not render dxgate OTEL endpoint:\n%s", rendered[4])
 	}
+
 }
 
 // TestKubeGatewayTemplateRendersHighAvailabilityResources covers the path a
@@ -874,7 +875,6 @@ func TestResolveGatewayObservabilityTelemetryHierarchy(t *testing.T) {
 	if cfg.OtelTags != `{"userId":"unknown"}` {
 		t.Fatalf("otel tags = %q", cfg.OtelTags)
 	}
-
 	resources = append(resources, telemetryconfig.Resource{
 		Name: "workload-override", Namespace: "app", CreationTimestamp: time.Unix(3, 0),
 		Spec: &apitelemetry.Telemetry{
diff --git a/go.mod b/go.mod
index 8089457e..44e1549a 100644
--- a/go.mod
+++ b/go.mod
@@ -17,6 +17,10 @@ module github.com/apache/dubbo-kubernetes
 
 go 1.25.12
 
+replace github.com/kdubbo/api => ../api
+
+replace github.com/kdubbo/client-go => ../client-go
+
 require (
 	k8s.io/apimachinery v0.34.1
 	k8s.io/client-go v0.34.1
@@ -42,8 +46,8 @@ require (
 	github.com/hashicorp/go-multierror v1.1.1
 	github.com/hashicorp/golang-lru/v2 v2.0.7
 	github.com/kdubbo/api v0.0.0-20260811085311-7752d1da2bcb
-	github.com/kdubbo/client-go v0.0.0-20260811085609-07dfedad5b33
-	github.com/kdubbo/xds-api v0.0.0-20260811085311-5a7b086ecdc6
+	github.com/kdubbo/client-go v0.0.0-20260809042806-04a31db14165
+	github.com/kdubbo/xds-api v0.0.0-20260809042456-0d57cc43a21a
 	github.com/prometheus/client_golang v1.23.2
 	github.com/prometheus/client_model v0.6.2
 	github.com/spf13/cobra v1.10.2
diff --git a/go.sum b/go.sum
index 45722ad4..bab6d2cf 100644
--- a/go.sum
+++ b/go.sum
@@ -154,12 +154,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/kdubbo/api v0.0.0-20260811085311-7752d1da2bcb h1:BYIqwRc/1D9xsHXonODshRwgEgMIip6nAWF1oMuWFhI=
-github.com/kdubbo/api v0.0.0-20260811085311-7752d1da2bcb/go.mod h1:8BtJiIovg7QCPsCxXcw3gDf922VcvYq5ihOSvj49Rq8=
-github.com/kdubbo/client-go v0.0.0-20260811085609-07dfedad5b33 h1:Xtv/mwzQdww5uGk0t+En7X843chTKgFWen1DCDmSq8s=
-github.com/kdubbo/client-go v0.0.0-20260811085609-07dfedad5b33/go.mod h1:J7zo0kp1Q+2JanfPHasOvasgsCJ+I5RZpd42DhcMMuw=
-github.com/kdubbo/xds-api v0.0.0-20260811085311-5a7b086ecdc6 h1:Oodawr6d7r8N6hXImlXkpMs9+dECFbRWCZZ0nIiG00k=
-github.com/kdubbo/xds-api v0.0.0-20260811085311-5a7b086ecdc6/go.mod h1:o2HDUgL1ntaDbWomZ4cD2tt8jBamuG2qRtjXOa1zZ0Q=
+github.com/kdubbo/xds-api v0.0.0-20260809042456-0d57cc43a21a h1:stTvOOGy4r6DoxquO928mB9AGGoFBvjVHxqAGIGiSkI=
+github.com/kdubbo/xds-api v0.0.0-20260809042456-0d57cc43a21a/go.mod h1:o2HDUgL1ntaDbWomZ4cD2tt8jBamuG2qRtjXOa1zZ0Q=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
diff --git a/manifests/charts/base/files/crd-all.gen.yaml b/manifests/charts/base/files/crd-all.gen.yaml
index f95f087b..6ca35631 100644
--- a/manifests/charts/base/files/crd-all.gen.yaml
+++ b/manifests/charts/base/files/crd-all.gen.yaml
@@ -1593,14 +1593,74 @@ spec:
       jsonPath: .metadata.creationTimestamp
       name: Age
       type: date
-    name: v1alpha1
+    name: v1alpha3
     schema:
       openAPIV3Schema:
         properties:
           spec:
-            description: 'Telemetry configuration for workloads. See more details
-              at: '
+            description: 'Telemetry configuration for Inherent workloads. See more
+              details at: '
             properties:
+              metrics:
+                description: Metrics configures metric generation for selected workloads.
+                items:
+                  properties:
+                    enabled:
+                      description: Controls metric generation.
+                      nullable: true
+                      type: boolean
+                    providers:
+                      description: Providers used for metric reporting.
+                      items:
+                        properties:
+                          name:
+                            description: REQUIRED.
+                            type: string
+                        type: object
+                      type: array
+                    rules:
+                      description: Rules customize standard metrics.
+                      items:
+                        properties:
+                          metric:
+                            description: |-
+                              REQUIRED.
+
+                              Valid Options: REQUEST_COUNT
+                            enum:
+                            - STANDARD_METRIC_UNSPECIFIED
+                            - REQUEST_COUNT
+                            type: string
+                          scope:
+                            description: |-
+                              REQUIRED.
+
+                              Valid Options: CLIENT, SERVER, CLIENT_AND_SERVER
+                            enum:
+                            - METRIC_SCOPE_UNSPECIFIED
+                            - CLIENT
+                            - SERVER
+                            - CLIENT_AND_SERVER
+                            type: string
+                          tags:
+                            additionalProperties:
+                              properties:
+                                action:
+                                  description: |-
+                                    REQUIRED.
+
+                                    Valid Options: REMOVE
+                                  enum:
+                                  - ACTION_UNSPECIFIED
+                                  - REMOVE
+                                  type: string
+                              type: object
+                            description: Tag overrides keyed by metric tag name.
+                            type: object
+                        type: object
+                      type: array
+                  type: object
+                type: array
               selector:
                 description: The selector determines the workloads to apply the Telemetry
                   on.
@@ -1621,12 +1681,11 @@ spec:
                       rule: self.all(key, key.size() != 0)
                 type: object
               tracing:
-                description: Tracing configures the tracing behavior for all selected
-                  workloads.
+                description: Tracing configures tracing behavior for selected workloads.
                 items:
                   properties:
                     disableSpanReporting:
-                      description: Controls span reporting.
+                      description: Disables span reporting for selected workloads.
                       nullable: true
                       type: boolean
                     providers:
@@ -1639,8 +1698,7 @@ spec:
                         type: object
                       type: array
                     randomSamplingPercentage:
-                      description: Controls the rate at which traffic will be selected
-                        for tracing if no prior sampling decision has been made.
+                      description: Sampling percentage in range [0.0, 100.0].
                       format: double
                       nullable: true
                       type: number
diff --git a/pkg/config/schema/codegen/templates/clients.go.tmpl b/pkg/config/schema/codegen/templates/clients.go.tmpl
index 89d314fb..7f8be9d5 100644
--- a/pkg/config/schema/codegen/templates/clients.go.tmpl
+++ b/pkg/config/schema/codegen/templates/clients.go.tmpl
@@ -19,7 +19,7 @@ import (
 
 	apigithubcomapachedubbokubernetesapinetworkingv1alpha3 "github.com/kdubbo/client-go/pkg/apis/networking/v1alpha3"
 	apigithubcomapachedubbokubernetesapisecurityv1alpha3 "github.com/kdubbo/client-go/pkg/apis/security/v1alpha3"
-	apigithubcomapachedubbokubernetesapitelemetryv1alpha1 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha1"
+	apigithubcomapachedubbokubernetesapitelemetryv1alpha3 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha3"
 {{- range .Packages}}
 	{{.ImportName}} "{{.PackageName}}"
 {{- end}}
diff --git a/pkg/config/schema/codegen/templates/crdclient.go.tmpl b/pkg/config/schema/codegen/templates/crdclient.go.tmpl
index d2edadec..0017546e 100644
--- a/pkg/config/schema/codegen/templates/crdclient.go.tmpl
+++ b/pkg/config/schema/codegen/templates/crdclient.go.tmpl
@@ -16,7 +16,7 @@ import (
 
 	apigithubcomapachedubbokubernetesapinetworkingv1alpha3 "github.com/kdubbo/client-go/pkg/apis/networking/v1alpha3"
 	apigithubcomapachedubbokubernetesapisecurityv1alpha3 "github.com/kdubbo/client-go/pkg/apis/security/v1alpha3"
-	apigithubcomapachedubbokubernetesapitelemetryv1alpha1 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha1"
+	apigithubcomapachedubbokubernetesapitelemetryv1alpha3 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha3"
 {{- range .Packages}}
 	{{.ImportName}} "{{.PackageName}}"
 {{- end}}
diff --git a/pkg/config/schema/codegen/templates/types.go.tmpl b/pkg/config/schema/codegen/templates/types.go.tmpl
index 33cd99e0..d4e6a19e 100644
--- a/pkg/config/schema/codegen/templates/types.go.tmpl
+++ b/pkg/config/schema/codegen/templates/types.go.tmpl
@@ -10,7 +10,7 @@ import (
 {{- end}}
 	apigithubcomapachedubbokubernetesapinetworkingv1alpha3 "github.com/kdubbo/client-go/pkg/apis/networking/v1alpha3"
 	apigithubcomapachedubbokubernetesapisecurityv1alpha3 "github.com/kdubbo/client-go/pkg/apis/security/v1alpha3"
-	apigithubcomapachedubbokubernetesapitelemetryv1alpha1 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha1"
+	apigithubcomapachedubbokubernetesapitelemetryv1alpha3 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha3"
 )
 
 func getGvk(obj any) (config.GroupVersionKind, bool) {
diff --git a/pkg/config/schema/collections/collections.gen.go b/pkg/config/schema/collections/collections.gen.go
index 9d82b78a..3b31b9b2 100755
--- a/pkg/config/schema/collections/collections.gen.go
+++ b/pkg/config/schema/collections/collections.gen.go
@@ -15,7 +15,7 @@ import (
 	githubcomkdubboapimetav1alpha1 "github.com/kdubbo/api/meta/v1alpha1"
 	githubcomkdubboapinetworkingv1alpha3 "github.com/kdubbo/api/networking/v1alpha3"
 	githubcomkdubboapisecurityv1alpha3 "github.com/kdubbo/api/security/v1alpha3"
-	githubcomkdubboapitelemetryv1alpha1 "github.com/kdubbo/api/telemetry/v1alpha1"
+	githubcomkdubboapitelemetryv1alpha3 "github.com/kdubbo/api/telemetry/v1alpha3"
 	k8sioapiadmissionregistrationv1 "k8s.io/api/admissionregistration/v1"
 	k8sioapiappsv1 "k8s.io/api/apps/v1"
 	k8sioapiautoscalingv2 "k8s.io/api/autoscaling/v2"
@@ -514,10 +514,10 @@ var (
 		Group:      "telemetry.dubbo.apache.org",
 		Kind:       "Telemetry",
 		Plural:     "telemetries",
-		Version:    "v1alpha1",
-		Proto:      "dubbo.telemetry.v1alpha1.Telemetry", StatusProto: "dubbo.meta.v1alpha1.DubboStatus",
-		ReflectType: reflect.TypeOf(&githubcomkdubboapitelemetryv1alpha1.Telemetry{}).Elem(), StatusType: reflect.TypeOf(&githubcomkdubboapimetav1alpha1.DubboStatus{}).Elem(),
-		ProtoPackage: "github.com/kdubbo/api/telemetry/v1alpha1", StatusPackage: "github.com/kdubbo/api/meta/v1alpha1",
+		Version:    "v1alpha3",
+		Proto:      "dubbo.telemetry.v1alpha3.Telemetry", StatusProto: "dubbo.meta.v1alpha1.DubboStatus",
+		ReflectType: reflect.TypeOf(&githubcomkdubboapitelemetryv1alpha3.Telemetry{}).Elem(), StatusType: reflect.TypeOf(&githubcomkdubboapimetav1alpha1.DubboStatus{}).Elem(),
+		ProtoPackage: "github.com/kdubbo/api/telemetry/v1alpha3", StatusPackage: "github.com/kdubbo/api/meta/v1alpha1",
 		ClusterScoped: false,
 		Synthetic:     false,
 		Builtin:       false,
diff --git a/pkg/config/schema/gvk/resources.gen.go b/pkg/config/schema/gvk/resources.gen.go
index b094ac5c..6b5aba6c 100755
--- a/pkg/config/schema/gvk/resources.gen.go
+++ b/pkg/config/schema/gvk/resources.gen.go
@@ -46,7 +46,7 @@ var (
 	ServiceActivationPolicy        = config.GroupVersionKind{Group: "networking.dubbo.apache.org", Version: "v1alpha3", Kind: "ServiceActivationPolicy"}
 	ServiceEntry                   = config.GroupVersionKind{Group: "networking.dubbo.apache.org", Version: "v1alpha3", Kind: "ServiceEntry"}
 	StatefulSet                    = config.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}
-	Telemetry                      = config.GroupVersionKind{Group: "telemetry.dubbo.apache.org", Version: "v1alpha1", Kind: "Telemetry"}
+	Telemetry                      = config.GroupVersionKind{Group: "telemetry.dubbo.apache.org", Version: "v1alpha3", Kind: "Telemetry"}
 	ValidatingWebhookConfiguration = config.GroupVersionKind{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfiguration"}
 	WorkloadEntry                  = config.GroupVersionKind{Group: "networking.dubbo.apache.org", Version: "v1alpha3", Kind: "WorkloadEntry"}
 )
diff --git a/pkg/config/schema/gvr/resources.gen.go b/pkg/config/schema/gvr/resources.gen.go
index b71d600f..69c4e42d 100755
--- a/pkg/config/schema/gvr/resources.gen.go
+++ b/pkg/config/schema/gvr/resources.gen.go
@@ -41,7 +41,7 @@ var (
 	ServiceActivationPolicy        = schema.GroupVersionResource{Group: "networking.dubbo.apache.org", Version: "v1alpha3", Resource: "serviceactivationpolicies"}
 	ServiceEntry                   = schema.GroupVersionResource{Group: "networking.dubbo.apache.org", Version: "v1alpha3", Resource: "serviceentries"}
 	StatefulSet                    = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"}
-	Telemetry                      = schema.GroupVersionResource{Group: "telemetry.dubbo.apache.org", Version: "v1alpha1", Resource: "telemetries"}
+	Telemetry                      = schema.GroupVersionResource{Group: "telemetry.dubbo.apache.org", Version: "v1alpha3", Resource: "telemetries"}
 	ValidatingWebhookConfiguration = schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1", Resource: "validatingwebhookconfigurations"}
 	WorkloadEntry                  = schema.GroupVersionResource{Group: "networking.dubbo.apache.org", Version: "v1alpha3", Resource: "workloadentries"}
 )
diff --git a/pkg/config/schema/kubeclient/resources.gen.go b/pkg/config/schema/kubeclient/resources.gen.go
index 61e5a3ab..be1bdd0a 100755
--- a/pkg/config/schema/kubeclient/resources.gen.go
+++ b/pkg/config/schema/kubeclient/resources.gen.go
@@ -19,7 +19,7 @@ import (
 
 	apigithubcomapachedubbokubernetesapinetworkingv1alpha3 "github.com/kdubbo/client-go/pkg/apis/networking/v1alpha3"
 	apigithubcomapachedubbokubernetesapisecurityv1alpha3 "github.com/kdubbo/client-go/pkg/apis/security/v1alpha3"
-	apigithubcomapachedubbokubernetesapitelemetryv1alpha1 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha1"
+	apigithubcomapachedubbokubernetesapitelemetryv1alpha3 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha3"
 	k8sioapiadmissionregistrationv1 "k8s.io/api/admissionregistration/v1"
 	k8sioapiappsv1 "k8s.io/api/apps/v1"
 	k8sioapiautoscalingv2 "k8s.io/api/autoscaling/v2"
@@ -94,8 +94,8 @@ func GetWriteClient[T runtime.Object](c ClientGetter, namespace string) ktypes.W
 		return c.Dubbo().NetworkingV1alpha3().ServiceEntries(namespace).(ktypes.WriteAPI[T])
 	case *k8sioapiappsv1.StatefulSet:
 		return c.Kube().AppsV1().StatefulSets(namespace).(ktypes.WriteAPI[T])
-	case *apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry:
-		return c.Dubbo().TelemetryV1alpha1().Telemetries(namespace).(ktypes.WriteAPI[T])
+	case *apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry:
+		return c.Dubbo().TelemetryV1alpha3().Telemetries(namespace).(ktypes.WriteAPI[T])
 	case *k8sioapiadmissionregistrationv1.ValidatingWebhookConfiguration:
 		return c.Kube().AdmissionregistrationV1().ValidatingWebhookConfigurations().(ktypes.WriteAPI[T])
 	case *apigithubcomapachedubbokubernetesapinetworkingv1alpha3.WorkloadEntry:
@@ -167,8 +167,8 @@ func GetClient[T, TL runtime.Object](c ClientGetter, namespace string) ktypes.Re
 		return c.Dubbo().NetworkingV1alpha3().ServiceEntries(namespace).(ktypes.ReadWriteAPI[T, TL])
 	case *k8sioapiappsv1.StatefulSet:
 		return c.Kube().AppsV1().StatefulSets(namespace).(ktypes.ReadWriteAPI[T, TL])
-	case *apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry:
-		return c.Dubbo().TelemetryV1alpha1().Telemetries(namespace).(ktypes.ReadWriteAPI[T, TL])
+	case *apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry:
+		return c.Dubbo().TelemetryV1alpha3().Telemetries(namespace).(ktypes.ReadWriteAPI[T, TL])
 	case *k8sioapiadmissionregistrationv1.ValidatingWebhookConfiguration:
 		return c.Kube().AdmissionregistrationV1().ValidatingWebhookConfigurations().(ktypes.ReadWriteAPI[T, TL])
 	case *apigithubcomapachedubbokubernetesapinetworkingv1alpha3.WorkloadEntry:
@@ -241,7 +241,7 @@ func gvrToObject(g schema.GroupVersionResource) runtime.Object {
 	case gvr.StatefulSet:
 		return &k8sioapiappsv1.StatefulSet{}
 	case gvr.Telemetry:
-		return &apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry{}
+		return &apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry{}
 	case gvr.ValidatingWebhookConfiguration:
 		return &k8sioapiadmissionregistrationv1.ValidatingWebhookConfiguration{}
 	case gvr.WorkloadEntry:
@@ -468,10 +468,10 @@ func getInformerFiltered(c ClientGetter, opts ktypes.InformerOptions, g schema.G
 		}
 	case gvr.Telemetry:
 		l = func(options metav1.ListOptions) (runtime.Object, error) {
-			return c.Dubbo().TelemetryV1alpha1().Telemetries(opts.Namespace).List(context.Background(), options)
+			return c.Dubbo().TelemetryV1alpha3().Telemetries(opts.Namespace).List(context.Background(), options)
 		}
 		w = func(options metav1.ListOptions) (watch.Interface, error) {
-			return c.Dubbo().TelemetryV1alpha1().Telemetries(opts.Namespace).Watch(context.Background(), options)
+			return c.Dubbo().TelemetryV1alpha3().Telemetries(opts.Namespace).Watch(context.Background(), options)
 		}
 	case gvr.ValidatingWebhookConfiguration:
 		l = func(options metav1.ListOptions) (runtime.Object, error) {
diff --git a/pkg/config/schema/kubetypes/resources.gen.go b/pkg/config/schema/kubetypes/resources.gen.go
index ea73932a..5499ba44 100755
--- a/pkg/config/schema/kubetypes/resources.gen.go
+++ b/pkg/config/schema/kubetypes/resources.gen.go
@@ -8,10 +8,10 @@ import (
 	githubcomkdubboapimeshv1alpha1 "github.com/kdubbo/api/mesh/v1alpha1"
 	githubcomkdubboapinetworkingv1alpha3 "github.com/kdubbo/api/networking/v1alpha3"
 	githubcomkdubboapisecurityv1alpha3 "github.com/kdubbo/api/security/v1alpha3"
-	githubcomkdubboapitelemetryv1alpha1 "github.com/kdubbo/api/telemetry/v1alpha1"
+	githubcomkdubboapitelemetryv1alpha3 "github.com/kdubbo/api/telemetry/v1alpha3"
 	apigithubcomapachedubbokubernetesapinetworkingv1alpha3 "github.com/kdubbo/client-go/pkg/apis/networking/v1alpha3"
 	apigithubcomapachedubbokubernetesapisecurityv1alpha3 "github.com/kdubbo/client-go/pkg/apis/security/v1alpha3"
-	apigithubcomapachedubbokubernetesapitelemetryv1alpha1 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha1"
+	apigithubcomapachedubbokubernetesapitelemetryv1alpha3 "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha3"
 	k8sioapiadmissionregistrationv1 "k8s.io/api/admissionregistration/v1"
 	k8sioapiappsv1 "k8s.io/api/apps/v1"
 	k8sioapiautoscalingv2 "k8s.io/api/autoscaling/v2"
@@ -104,9 +104,9 @@ func getGvk(obj any) (config.GroupVersionKind, bool) {
 		return gvk.ServiceEntry, true
 	case *k8sioapiappsv1.StatefulSet:
 		return gvk.StatefulSet, true
-	case *githubcomkdubboapitelemetryv1alpha1.Telemetry:
+	case *githubcomkdubboapitelemetryv1alpha3.Telemetry:
 		return gvk.Telemetry, true
-	case *apigithubcomapachedubbokubernetesapitelemetryv1alpha1.Telemetry:
+	case *apigithubcomapachedubbokubernetesapitelemetryv1alpha3.Telemetry:
 		return gvk.Telemetry, true
 	case *k8sioapiadmissionregistrationv1.ValidatingWebhookConfiguration:
 		return gvk.ValidatingWebhookConfiguration, true
diff --git a/pkg/config/schema/metadata.yaml b/pkg/config/schema/metadata.yaml
index c238b616..4f5d0d40 100644
--- a/pkg/config/schema/metadata.yaml
+++ b/pkg/config/schema/metadata.yaml
@@ -306,8 +306,8 @@ resources:
   - kind: Telemetry
     plural: "telemetries"
     group: "telemetry.dubbo.apache.org"
-    version: "v1alpha1"
-    proto: "dubbo.telemetry.v1alpha1.Telemetry"
-    protoPackage: "github.com/kdubbo/api/telemetry/v1alpha1"
+    version: "v1alpha3"
+    proto: "dubbo.telemetry.v1alpha3.Telemetry"
+    protoPackage: "github.com/kdubbo/api/telemetry/v1alpha3"
     statusProto: "dubbo.meta.v1alpha1.DubboStatus"
     statusProtoPackage: "github.com/kdubbo/api/meta/v1alpha1"
diff --git a/pkg/config/telemetry/telemetry.go b/pkg/config/telemetry/telemetry.go
index 5cce78d2..c243c930 100644
--- a/pkg/config/telemetry/telemetry.go
+++ b/pkg/config/telemetry/telemetry.go
@@ -19,18 +19,20 @@ package telemetry
 import (
 	"encoding/json"
 	"fmt"
+	"slices"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
 
 	"github.com/apache/dubbo-kubernetes/pkg/config"
-	api "github.com/kdubbo/api/telemetry/v1alpha1"
-	clientapi "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha1"
+	api "github.com/kdubbo/api/telemetry/v1alpha3"
+	clientapi "github.com/kdubbo/client-go/pkg/apis/telemetry/v1alpha3"
 )
 
 const (
 	LocalTraceProvider = "localtrace"
+	PrometheusProvider = "prometheus"
 	OTLPPort           = 4317
 )
 
@@ -46,12 +48,27 @@ type Tag struct {
 	Value string
 }
 
+type MetricTagOverride struct {
+	Name   string
+	Action api.TagOverride_Action
+}
+
+type MetricRule struct {
+	Metric api.StandardMetric
+	Scope  api.MetricScope
+	Tags   []MetricTagOverride
+}
+
 type EffectiveTracing struct {
 	Configured               bool
 	Providers                []string
 	Tags                     []Tag
 	RandomSamplingPercentage *float64
 	DisableSpanReporting     *bool
+	MetricsConfigured        bool
+	MetricProviders          []string
+	EnableMetrics            *bool
+	MetricRules              []MetricRule
 }
 
 func ResourcesFromConfigs(configs []config.Config) []Resource {
@@ -146,6 +163,47 @@ func matches(selector, labels map[string]string) bool {
 }
 
 func apply(result *EffectiveTracing, spec *api.Telemetry) {
+	for _, metrics := range spec.GetMetrics() {
+		if metrics == nil {
+			continue
+		}
+		result.MetricsConfigured = true
+		if len(metrics.GetProviders()) > 0 {
+			result.MetricProviders = make([]string, 0, len(metrics.GetProviders()))
+			for _, provider := range metrics.GetProviders() {
+				result.MetricProviders = append(result.MetricProviders, provider.GetName())
+			}
+		}
+		if enabled := metrics.GetEnabled(); enabled != nil {
+			value := enabled.GetValue()
+			result.EnableMetrics = &value
+		}
+		if len(metrics.GetRules()) > 0 {
+			result.MetricRules = make([]MetricRule, 0, len(metrics.GetRules()))
+			for _, rule := range metrics.GetRules() {
+				if rule == nil {
+					continue
+				}
+				tagNames := make([]string, 0, len(rule.GetTags()))
+				for name := range rule.GetTags() {
+					tagNames = append(tagNames, name)
+				}
+				sort.Strings(tagNames)
+				effective := MetricRule{
+					Metric: rule.GetMetric(),
+					Scope:  rule.GetScope(),
+					Tags:   make([]MetricTagOverride, 0, len(tagNames)),
+				}
+				for _, name := range tagNames {
+					effective.Tags = append(effective.Tags, MetricTagOverride{
+						Name:   name,
+						Action: rule.GetTags()[name].GetAction(),
+					})
+				}
+				result.MetricRules = append(result.MetricRules, effective)
+			}
+		}
+	}
 	for _, tracing := range spec.GetTracing() {
 		if tracing == nil {
 			continue
@@ -174,6 +232,23 @@ func apply(result *EffectiveTracing, spec *api.Telemetry) {
 	}
 }
 
+func (t EffectiveTracing) MetricsEnabled() bool {
+	if !t.MetricsConfigured {
+		return false
+	}
+	if t.EnableMetrics != nil {
+		return *t.EnableMetrics
+	}
+	return slices.Contains(t.MetricProviders, PrometheusProvider)
+}
+
+func (t EffectiveTracing) MetricsProvider() string {
+	if len(t.MetricProviders) == 0 {
+		return ""
+	}
+	return t.MetricProviders[0]
+}
+
 func (t EffectiveTracing) Disabled() bool {
 	return t.DisableSpanReporting != nil && *t.DisableSpanReporting
 }
diff --git a/pkg/config/telemetry/telemetry_test.go b/pkg/config/telemetry/telemetry_test.go
index 13ed2f44..b96c754b 100644
--- a/pkg/config/telemetry/telemetry_test.go
+++ b/pkg/config/telemetry/telemetry_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 	"time"
 
-	api "github.com/kdubbo/api/telemetry/v1alpha1"
+	api "github.com/kdubbo/api/telemetry/v1alpha3"
 	typeapi "github.com/kdubbo/api/type/v1alpha3"
 	"google.golang.org/protobuf/types/known/wrapperspb"
 )
@@ -33,6 +33,15 @@ func TestResolveTelemetryLevels(t *testing.T) {
 				Providers:                []*api.Tracing_TracingProvider{{Name: "localtrace"}},
 				Tags:                     []*api.Tracing_Tag{{Name: "foo", Value: "bar"}},
 				RandomSamplingPercentage: wrapperspb.Double(100),
+			}}, Metrics: []*api.Metrics{{
+				Providers: []*api.Metrics_MetricsProvider{{Name: PrometheusProvider}},
+				Rules: []*api.MetricRule{{
+					Metric: api.StandardMetric_REQUEST_COUNT,
+					Scope:  api.MetricScope_CLIENT_AND_SERVER,
+					Tags: map[string]*api.TagOverride{
+						"grpc_response_status": {Action: api.TagOverride_REMOVE},
+					},
+				}},
 			}}},
 		},
 		{
@@ -63,6 +72,71 @@ func TestResolveTelemetryLevels(t *testing.T) {
 	if !got.Disabled() {
 		t.Fatal("workload override did not disable span reporting")
 	}
+	if !got.MetricsEnabled() || got.MetricsProvider() != PrometheusProvider {
+		t.Fatalf("metrics = enabled:%v provider:%q", got.MetricsEnabled(), got.MetricsProvider())
+	}
+	if len(got.MetricRules) != 1 ||
+		got.MetricRules[0].Metric != api.StandardMetric_REQUEST_COUNT ||
+		got.MetricRules[0].Scope != api.MetricScope_CLIENT_AND_SERVER ||
+		len(got.MetricRules[0].Tags) != 1 ||
+		got.MetricRules[0].Tags[0].Name != "grpc_response_status" ||
+		got.MetricRules[0].Tags[0].Action != api.TagOverride_REMOVE {
+		t.Fatalf("metric rules = %#v", got.MetricRules)
+	}
+}
+
+func TestResolveMetricsDisableOverride(t *testing.T) {
+	resources := []Resource{
+		{
+			Name: "mesh-default", Namespace: "dubbo-system",
+			Spec: &api.Telemetry{Metrics: []*api.Metrics{{
+				Providers: []*api.Metrics_MetricsProvider{{Name: PrometheusProvider}},
+			}}},
+		},
+		{
+			Name: "namespace-disable", Namespace: "myapp",
+			Spec: &api.Telemetry{Metrics: []*api.Metrics{{
+				Enabled: wrapperspb.Bool(false),
+			}}},
+		},
+	}
+
+	got := Resolve(resources, "dubbo-system", "myapp", nil)
+	if got.MetricsEnabled() {
+		t.Fatal("namespace override did not disable metrics")
+	}
+	if got.MetricsProvider() != PrometheusProvider {
+		t.Fatalf("provider = %q, want inherited prometheus", got.MetricsProvider())
+	}
+}
+
+func TestResolveMetricsRulesOverride(t *testing.T) {
+	resources := []Resource{
+		{
+			Name: "mesh-default", Namespace: "dubbo-system",
+			Spec: &api.Telemetry{Metrics: []*api.Metrics{{
+				Providers: []*api.Metrics_MetricsProvider{{Name: PrometheusProvider}},
+				Rules: []*api.MetricRule{{
+					Metric: api.StandardMetric_REQUEST_COUNT,
+					Scope:  api.MetricScope_CLIENT,
+				}},
+			}}},
+		},
+		{
+			Name: "namespace-rules", Namespace: "myapp",
+			Spec: &api.Telemetry{Metrics: []*api.Metrics{{
+				Rules: []*api.MetricRule{{
+					Metric: api.StandardMetric_REQUEST_COUNT,
+					Scope:  api.MetricScope_SERVER,
+				}},
+			}}},
+		},
+	}
+
+	got := Resolve(resources, "dubbo-system", "myapp", nil)
+	if len(got.MetricRules) != 1 || got.MetricRules[0].Scope != api.MetricScope_SERVER {
+		t.Fatalf("metric rules = %#v, want namespace replacement", got.MetricRules)
+	}
 }
 
 func TestMeshlevelSelectorIsIgnored(t *testing.T) {
diff --git a/pkg/config/validation/validators.go b/pkg/config/validation/validators.go
index 20831327..ce82afb2 100644
--- a/pkg/config/validation/validators.go
+++ b/pkg/config/validation/validators.go
@@ -28,10 +28,11 @@ import (
 	"github.com/apache/dubbo-kubernetes/pkg/config/constants"
 	"github.com/apache/dubbo-kubernetes/pkg/config/labels"
 	"github.com/apache/dubbo-kubernetes/pkg/config/protocol"
+	telemetryconfig "github.com/apache/dubbo-kubernetes/pkg/config/telemetry"
 	"github.com/apache/dubbo-kubernetes/pkg/config/visibility"
 	networking "github.com/kdubbo/api/networking/v1alpha3"
 	security "github.com/kdubbo/api/security/v1alpha3"
-	telemetry "github.com/kdubbo/api/telemetry/v1alpha1"
+	telemetry "github.com/kdubbo/api/telemetry/v1alpha3"
 	kvalidation "k8s.io/apimachinery/pkg/util/validation"
 )
 
@@ -585,6 +586,58 @@ var ValidateTelemetry = RegisterValidateFunc("ValidateTelemetry",
 		if cfg.Namespace == constants.DubboSystemNamespace && spec.GetSelector() != nil {
 			v = appendValidation(v, fmt.Errorf("selector is not allowed on meshlevel Telemetry in namespace %q", constants.DubboSystemNamespace))
 		}
+		for i, m := range spec.GetMetrics() {
+			if m == nil {
+				v = appendValidation(v, fmt.Errorf("metrics[%d] must not be null", i))
+				continue
+			}
+			providers := map[string]struct{}{}
+			for j, p := range m.GetProviders() {
+				name := strings.TrimSpace(p.GetName())
+				if name == "" {
+					v = appendValidation(v, fmt.Errorf("metrics[%d].providers[%d].name must be set", i, j))
+					continue
+				}
+				if name != telemetryconfig.PrometheusProvider {
+					v = appendValidation(v, fmt.Errorf("metrics[%d].providers[%d].name %q is unsupported", i, j, name))
+				}
+				if _, found := providers[name]; found {
+					v = appendValidation(v, fmt.Errorf("metrics[%d].providers[%d].name %q is duplicated", i, j, name))
+				}
+				providers[name] = struct{}{}
+			}
+			rules := map[string]struct{}{}
+			for j, rule := range m.GetRules() {
+				if rule == nil {
+					v = appendValidation(v, fmt.Errorf("metrics[%d].rules[%d] must not be null", i, j))
+					continue
+				}
+				if rule.GetMetric() == telemetry.StandardMetric_STANDARD_METRIC_UNSPECIFIED {
+					v = appendValidation(v, fmt.Errorf("metrics[%d].rules[%d].metric must be set", i, j))
+				}
+				if rule.GetScope() == telemetry.MetricScope_METRIC_SCOPE_UNSPECIFIED {
+					v = appendValidation(v, fmt.Errorf("metrics[%d].rules[%d].scope must be set", i, j))
+				}
+				key := fmt.Sprintf("%d/%d", rule.GetMetric(), rule.GetScope())
+				if _, found := rules[key]; found {
+					v = appendValidation(v, fmt.Errorf("metrics[%d].rules[%d] duplicates metric %s with scope %s",
+						i, j, rule.GetMetric(), rule.GetScope()))
+				}
+				rules[key] = struct{}{}
+				for name, override := range rule.GetTags() {
+					if strings.TrimSpace(name) == "" {
+						v = appendValidation(v, fmt.Errorf("metrics[%d].rules[%d].tags contains an empty name", i, j))
+					}
+					if override == nil {
+						v = appendValidation(v, fmt.Errorf("metrics[%d].rules[%d].tags[%q] must not be null", i, j, name))
+						continue
+					}
+					if override.GetAction() != telemetry.TagOverride_REMOVE {
+						v = appendValidation(v, fmt.Errorf("metrics[%d].rules[%d].tags[%q].action must be REMOVE", i, j, name))
+					}
+				}
+			}
+		}
 		for i, t := range spec.GetTracing() {
 			if t == nil {
 				v = appendValidation(v, fmt.Errorf("tracing[%d] must not be null", i))
diff --git a/pkg/config/validation/validators_test.go b/pkg/config/validation/validators_test.go
index 179903c9..30212f26 100644
--- a/pkg/config/validation/validators_test.go
+++ b/pkg/config/validation/validators_test.go
@@ -27,7 +27,7 @@ import (
 	"github.com/apache/dubbo-kubernetes/pkg/config"
 	networking "github.com/kdubbo/api/networking/v1alpha3"
 	security "github.com/kdubbo/api/security/v1alpha3"
-	telemetry "github.com/kdubbo/api/telemetry/v1alpha1"
+	telemetry "github.com/kdubbo/api/telemetry/v1alpha3"
 	typev1alpha3 "github.com/kdubbo/api/type/v1alpha3"
 )
 
@@ -617,6 +617,60 @@ func TestValidateTelemetry(t *testing.T) {
 			},
 			wantErr: false,
 		},
+		{
+			name: "valid metrics provider",
+			spec: &telemetry.Telemetry{Metrics: []*telemetry.Metrics{{
+				Providers: []*telemetry.Metrics_MetricsProvider{{Name: "prometheus"}},
+				Enabled:   wrapperspb.Bool(true),
+				Rules: []*telemetry.MetricRule{{
+					Metric: telemetry.StandardMetric_REQUEST_COUNT,
+					Scope:  telemetry.MetricScope_CLIENT_AND_SERVER,
+					Tags: map[string]*telemetry.TagOverride{
+						"grpc_response_status": {Action: telemetry.TagOverride_REMOVE},
+					},
+				}},
+			}}},
+			wantErr: false,
+		},
+		{
+			name: "metrics rule without metric",
+			spec: &telemetry.Telemetry{Metrics: []*telemetry.Metrics{{
+				Rules: []*telemetry.MetricRule{{Scope: telemetry.MetricScope_SERVER}},
+			}}},
+			wantErr: true,
+		},
+		{
+			name: "metrics rule without scope",
+			spec: &telemetry.Telemetry{Metrics: []*telemetry.Metrics{{
+				Rules: []*telemetry.MetricRule{{Metric: telemetry.StandardMetric_REQUEST_COUNT}},
+			}}},
+			wantErr: true,
+		},
+		{
+			name: "metrics tag without action",
+			spec: &telemetry.Telemetry{Metrics: []*telemetry.Metrics{{
+				Rules: []*telemetry.MetricRule{{
+					Metric: telemetry.StandardMetric_REQUEST_COUNT,
+					Scope:  telemetry.MetricScope_CLIENT,
+					Tags:   map[string]*telemetry.TagOverride{"grpc_response_status": {}},
+				}},
+			}}},
+			wantErr: true,
+		},
+		{
+			name: "metrics provider without name",
+			spec: &telemetry.Telemetry{Metrics: []*telemetry.Metrics{{
+				Providers: []*telemetry.Metrics_MetricsProvider{{}},
+			}}},
+			wantErr: true,
+		},
+		{
+			name: "unsupported metrics provider",
+			spec: &telemetry.Telemetry{Metrics: []*telemetry.Metrics{{
+				Providers: []*telemetry.Metrics_MetricsProvider{{Name: "unknown"}},
+			}}},
+			wantErr: true,
+		},
 		{
 			name: "provider without name",
 			spec: &telemetry.Telemetry{
diff --git a/pkg/webhooks/server/server.go b/pkg/webhooks/server/server.go
index 31addff0..1647c33d 100644
--- a/pkg/webhooks/server/server.go
+++ b/pkg/webhooks/server/server.go
@@ -34,7 +34,7 @@ import (
 	"github.com/apache/dubbo-kubernetes/pkg/config/validation"
 	"github.com/apache/dubbo-kubernetes/pkg/kube"
 	"github.com/hashicorp/go-multierror"
-	telemetry "github.com/kdubbo/api/telemetry/v1alpha1"
+	telemetry "github.com/kdubbo/api/telemetry/v1alpha3"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/serializer"
diff --git a/pkg/webhooks/server/server_test.go b/pkg/webhooks/server/server_test.go
index fb2c3aba..cd7795e6 100644
--- a/pkg/webhooks/server/server_test.go
+++ b/pkg/webhooks/server/server_test.go
@@ -21,7 +21,7 @@ import (
 
 	"github.com/apache/dubbo-kubernetes/pkg/config"
 	"github.com/apache/dubbo-kubernetes/pkg/config/schema/gvk"
-	telemetry "github.com/kdubbo/api/telemetry/v1alpha1"
+	telemetry "github.com/kdubbo/api/telemetry/v1alpha3"
 )
 
 type fakeConfigLister struct {
diff --git a/samples/addons/telemetry.yaml b/samples/addons/telemetry.yaml
index 19fdab47..26d35c79 100644
--- a/samples/addons/telemetry.yaml
+++ b/samples/addons/telemetry.yaml
@@ -3,44 +3,19 @@
 # this work for additional information regarding copyright ownership.
 # The ASF licenses this file to You under the Apache License, Version 2.0.
 
-# Exactly one selectorless Telemetry is allowed in dubbo-system. It defines
-# the meshlevel defaults.
-apiVersion: telemetry.dubbo.apache.org/v1alpha1
+# Mesh-level Prometheus metrics for Inherent client and server reporters.
+apiVersion: telemetry.dubbo.apache.org/v1alpha3
 kind: Telemetry
 metadata:
-  name: mesh-default
+  name: metrics-tags
   namespace: dubbo-system
 spec:
-  tracing:
+  metrics:
   - providers:
-    - name: localtrace
-    tags:
-    - name: foo
-      value: bar
-    randomSamplingPercentage: 100
----
-# Fields present here replace the corresponding meshlevel field. Unspecified
-# fields, including providers and sampling, remain inherited.
-apiVersion: telemetry.dubbo.apache.org/v1alpha1
-kind: Telemetry
-metadata:
-  name: namespace-override
-  namespace: myapp
-spec:
-  tracing:
-  - tags:
-    - name: userId
-      value: unknown
----
-# A selector applies the final workload-level override inside its namespace.
-apiVersion: telemetry.dubbo.apache.org/v1alpha1
-kind: Telemetry
-metadata:
-  name: workload-override
-  namespace: myapp
-spec:
-  selector:
-    matchLabels:
-      app: frontend
-  tracing:
-  - disableSpanReporting: true
+    - name: prometheus
+    rules:
+    - metric: REQUEST_COUNT
+      scope: CLIENT_AND_SERVER
+      tags:
+        grpc_response_status:
+          action: REMOVE