Use SDKs to send metrics from applications

This document illustrates how you can send metrics directly from applications to the OTLP endpoint by using an SDK and the gRPC exporter, which is the recommended exporter for use with SDKs. The OTLP endpoint supports all of the OTLP protocols, including http/proto, http/json, and grpc. For more information, see Protocol support.

When you send application metrics directly to the OTLP endpoint, the OpenTelemetry Collector does not handle authentication and enrichment for you. When using SDKs to send metrics from applications, you need to do the following:

Before you begin

To run the examples, you must enable the necessary APIs and acquire authentication credentials.

Enable APIs

Enable the Cloud Monitoring API and the Telemetry API in your Google Cloud project by running the following command:

gcloud services enable monitoring.googleapis.com telemetry.googleapis.com

Get authentication credentials

Configure credentials for the OTLP gRPC exporter to use Google Application Default Credentials by running the following command:

gcloud auth application-default login

Language-specific examples

This section provides a selection of language-specific samples that create and write a counter metric. Select a tab for information about running the sample and to view the code.

Go

For information about configuring and running this example, see the README file for the Go sample.

// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
packagemain
import(
"context"
"errors"
"log"
"go.opentelemetry.io/contrib/detectors/gcp"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/metric"
sdkmetric"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
semconv"go.opentelemetry.io/otel/semconv/v1.37.0"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/oauth"
)
funcmain(){
ctx:=context.Background()
creds,err:=oauth.NewApplicationDefault(ctx)
iferr!=nil{
panic(err)
}
res,err:=resource.New(
ctx,
// Use the GCP resource detector to detect information about the GCP platform
resource.WithDetectors(gcp.NewDetector()),
// Keep the default detectors
resource.WithTelemetrySDK(),
// Add attributes from environment variables
resource.WithFromEnv(),
// Add your own custom attributes to identify your application
resource.WithAttributes(
semconv.ServiceNameKey.String("example-application"),
),
)
iferrors.Is(err,resource.ErrPartialResource)||errors.Is(err,resource.ErrSchemaURLConflict){
log.Println(err)
}elseiferr!=nil{
panic(err)
}
// Set endpoint with OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
metricExporter,err:=otlpmetricgrpc.New(ctx,otlpmetricgrpc.WithDialOption(grpc.WithPerRPCCredentials(creds)))
iferr!=nil{
panic(err)
}
meterProvider:=sdkmetric.NewMeterProvider(
sdkmetric.WithResource(res),
sdkmetric.WithReader(sdkmetric.NewPeriodicReader(metricExporter)),
)
deferfunc(){
iferr=meterProvider.Shutdown(ctx);err!=nil{
log.Println(err)
}
}()
meter:=meterProvider.Meter("github.com/GoogleCloudPlatform/opentelemetry-samples/golang/metric/otlpgrpc")
// Register counter value
counter,err:=meter.Int64Counter("counter-a")
iferr!=nil{
log.Fatalf("Failed to create counter: %v",err)
}
clabels:=[]attribute.KeyValue{attribute.Key("key").String("value")}
counter.Add(ctx,100,metric.WithAttributes(clabels...))
}

Java

For information about configuring and running this example, see the README file for the Java sample.

/*
 * Copyright 2026 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
packagecom.google.cloud.opentelemetry.samples.otlpmetric;
importio.opentelemetry.api.metrics.LongCounter;
importio.opentelemetry.sdk.OpenTelemetrySdk;
importio.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
importio.opentelemetry.sdk.common.CompletableResultCode;
importjava.util.Random;
importjava.util.concurrent.TimeUnit;
publicclass OTLPMetricExample{
privatestaticfinalStringINSTRUMENTATION_SCOPE_NAME=OTLPMetricExample.class.getName();
privatestaticfinalRandomRANDOM=newRandom();
privatestaticOpenTelemetrySdkopenTelemetrySdk;
privatestaticvoidmyUseCase(){
LongCountercounter=
openTelemetrySdk
.getMeter(INSTRUMENTATION_SCOPE_NAME)
.counterBuilder("example_counter")
.setDescription("Processed jobs")
.setUnit("1")
.build();
doWork(counter);
}
privatestaticvoiddoWork(LongCountercounter){
try{
for(inti=0;i < 10;i++){
counter.add(RANDOM.nextInt(100));
Thread.sleep(RANDOM.nextInt(1000));
}
}catch(InterruptedExceptione){
thrownewRuntimeException(e);
}
}
publicstaticvoidmain(String[]args){
// Configure the OpenTelemetry pipeline with Auto configuration
openTelemetrySdk=AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();
// Application-specific logic
myUseCase();
// Flush all buffered metrics
CompletableResultCodecompletableResultCode=openTelemetrySdk.getSdkMeterProvider().shutdown();
// wait till export finishes
completableResultCode.join(10000,TimeUnit.MILLISECONDS);
}
}

NodeJS

For information about configuring and running this example, see the README file for the NodeJS sample.

// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import*asopentelemetryfrom'@opentelemetry/sdk-node';
import{AuthClient,GoogleAuth}from'google-auth-library';
import{credentials}from'@grpc/grpc-js';
import{getResourceDetectorsasgetResourceDetectorsFromEnv}from'@opentelemetry/auto-instrumentations-node';
import{metrics,diag,DiagConsoleLogger}from'@opentelemetry/api';
import{OTLPMetricExporter}from'@opentelemetry/exporter-metrics-otlp-grpc';
import{PeriodicExportingMetricReader}from'@opentelemetry/sdk-metrics';
asyncfunctiongetAuthenticatedClient():Promise<AuthClient>{
constauth:GoogleAuth=newGoogleAuth({
scopes:'https://www.googleapis.com/auth/cloud-platform',
});
returnawaitauth.getClient();
}
diag.setLogger(
newDiagConsoleLogger(),
opentelemetry.core.diagLogLevelFromString(
opentelemetry.core.getStringFromEnv('OTEL_LOG_LEVEL'),
),
);
// App that exports metrics via gRPC with protobuf
asyncfunctionmain(){
constauthenticatedClient:AuthClient=awaitgetAuthenticatedClient();
constsdk=newopentelemetry.NodeSDK({
metricReaders:[
newPeriodicExportingMetricReader({
// Export metrics every 10 seconds. 5 seconds is the smallest sample period allowed by
// Cloud Monitoring.
exportIntervalMillis:10_000,
exporter:newOTLPMetricExporter({
credentials:credentials.combineChannelCredentials(
credentials.createSsl(),
credentials.createFromGoogleCredential(authenticatedClient),
),
}),
}),
],
resourceDetectors:getResourceDetectorsFromEnv(),
});
sdk.start();
// Create a meter
constmeter=metrics.getMeter('metrics-sample');
// Create a counter instrument
constcounter=meter.createCounter('metric_name');
// Record a measurement
counter.add(10,{key:'value'});
// Wait for the metric to be exported
awaitnewPromise(resolve=>{
setTimeout(resolve,11_000);
});
// Gracefully shut down the SDK to flush telemetry when the program exits
process.on('SIGTERM',()=>{
sdk
.shutdown()
.then(()=>diag.debug('OpenTelemetry SDK terminated'))
.catch(error=>diag.error('Error terminating OpenTelemetry SDK',error));
});
}
main().catch(console.error);

Python

For information about running this example, see the README file for the Python sample.

#!/usr/bin/env python3
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
importtime
importgoogle.auth
importgoogle.auth.transport.grpc
importgoogle.auth.transport.requests
importgrpc
fromgoogle.auth.transport.grpcimport AuthMetadataPlugin
fromopentelemetry.exporter.otlp.proto.grpc.metric_exporterimport (
 OTLPMetricExporter,
)
fromopentelemetry.resourcedetector.gcp_resource_detectorimport (
 GoogleCloudResourceDetector,
)
fromopentelemetry.sdk.resourcesimport get_aggregated_resources
fromopentelemetry.sdk.metricsimport MeterProvider
fromopentelemetry.sdk.metrics.exportimport PeriodicExportingMetricReader
"""
Sample script exporting OTLP metrics encoded as protobufs via gRPC.
"""
credentials, project_id = google.auth.default()
request = google.auth.transport.requests.Request()
resource = get_aggregated_resources([GoogleCloudResourceDetector(raise_on_error=True)])
auth_metadata_plugin = AuthMetadataPlugin(credentials=credentials, request=request)
channel_creds = grpc.composite_channel_credentials(
 grpc.ssl_channel_credentials(),
 grpc.metadata_call_credentials(auth_metadata_plugin),
)
exporter = OTLPMetricExporter(credentials=channel_creds)
reader = PeriodicExportingMetricReader(exporter)
provider = MeterProvider(metric_readers=[reader], resource=resource)
meter = provider.get_meter("gcp.otlp.sample")
counter = meter.create_counter("sample.otlp.counter")
defdo_work():
 counter.add(1)
 # do some work that the 'counter' will track
 print("doing some work...")
defdo_work_repeatedly():
 try:
 while True:
 do_work()
 time.sleep(1)
 except KeyboardInterrupt:
 print("\nKeyboard Interrupt: Stopping work.")
do_work_repeatedly()

Use the downward API for applications running as pods

If you are running the application as a pod in Kubernetes and aren't sending telemetry through the OpenTelemetry Collector, then make sure to use the downward API to set Kubernetes resource attributes:

env:
-name:POD_NAME
valueFrom:
fieldRef:
fieldPath:metadata.name
-name:NAMESPACE_NAME
valueFrom:
fieldRef:
fieldPath:metadata.namespace
-name:CONTAINER_NAME
value:my-container-name
-name:OTEL_RESOURCE_ATTRIBUTES
value:k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE_NAME),k8s.container.name=$(CONTAINER_NAME)

What's next

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026年08月31日 UTC.