-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add otlp metrics export from Google Cloud Run Functions (#377)
* Add otlp metrics export from Google Cloud Run Functions * Update the metric name * Update the README * Add newline at EOF * Update README * Update the copyright year in license header * Remove unused processors from the collector-config
- Loading branch information
Showing
7 changed files
with
381 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
# Exporting OTLP Metrics from Cloud Functions using OpenTelemetry Collector Sidecar | ||
|
||
This example shows how to export OpenTelemetry metrics from a Google Cloud Run Function | ||
to Google Managed Prometheus using OpenTelemetry Collector running as a sidecar. | ||
|
||
*Google Cloud Functions were renamed to Google Cloud Run Functions. For more information on what this change entails, see [here](https://cloud.google.com/blog/products/serverless/google-cloud-functions-is-now-cloud-run-functions).* | ||
|
||
Additional details on deploying functions on Cloud Run can be viewed [here](https://cloud.google.com/run/docs/deploy-functions). | ||
|
||
##### Important Note | ||
This example leverages the use of `always-allocated CPU` for Cloud Run Services, which may have different pricing implication compared to the default `CPU only allocated during request` option. | ||
Please see the [pricing table](https://cloud.google.com/run/pricing#tables) for differences and additional details. | ||
|
||
### Prerequisites | ||
|
||
##### Get Google Cloud Credentials on your machine | ||
|
||
```shell | ||
gcloud auth application-default login | ||
``` | ||
|
||
##### Export the Google Cloud Project ID to `GOOGLE_CLOUD_PROJECT` environment variable: | ||
|
||
```shell | ||
export GOOGLE_CLOUD_PROJECT="my-awesome-gcp-project-id" | ||
``` | ||
|
||
### Deploying the function and collector sidecar | ||
|
||
#### Prepare a docker image configured to run OpenTelemetry Collector | ||
|
||
Create a docker image that runs OpenTelemetry container as a sidecar. This image would be pushed to Google Cloud Artifact Repository. | ||
|
||
Follow these steps: | ||
|
||
1. Create an artifact repository in your GCP project: | ||
```shell | ||
gcloud artifacts repositories create otlp-cloud-run --repository-format=docker --location=us-central1 | ||
|
||
gcloud auth configure-docker us-central1-docker.pkg.dev | ||
``` | ||
2. Build & push the docker image with the collector: | ||
```shell | ||
# From the root of the repository | ||
cd examples/otlpmetrics-function/collector-deployment | ||
docker build . -t us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/otlp-cloud-run/otel-collector | ||
docker push us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/otlp-cloud-run/otel-collector | ||
``` | ||
|
||
#### Deploy & Run the Google Cloud Run Function: | ||
|
||
#### Build the JAR to deploy | ||
|
||
You first need to build the JAR that will be deployed as a function. To do so, run: | ||
|
||
```shell | ||
# From the examples-otlpmetrics-function directory | ||
gradle clean build shadowJar | ||
``` | ||
This command should generate a JAR named `hello-world-function.jar` in `out/deployment` directory. | ||
|
||
#### Deploy the function | ||
This example shows how to use the `gcloud` CLI to deploy the function along with the docker container: | ||
|
||
##### Using gcloud command | ||
|
||
```shell | ||
# From the examples-otlpmetrics-function directory | ||
gcloud beta run deploy cloud-func-helloworld \ | ||
--no-cpu-throttling \ | ||
--container app-function \ | ||
--function com.google.cloud.opentelemetry.examples.otlpmetricsfunction.HelloWorld \ | ||
--source=out/deployment \ | ||
--port=8080 \ | ||
--container otel-collector \ | ||
--image=us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/otlp-cloud-run/otel-collector:latest | ||
``` | ||
*Note that even though you are running `gcloud run deploy` instead of `gcloud functions deploy`, the `--function` flags instructs Cloud Run to deploy this service as a function.* | ||
|
||
After your Cloud Run Function has finished deploying, depending on your authentication setup, you can create a proxy to the deployed function on your localhost to facilitate testing: | ||
|
||
```shell | ||
# This will allow you to invoke your deployed function from http://localhost:8080 | ||
# Press Ctrl+C to interrupt the running proxy | ||
gcloud beta run services proxy cloud-func-helloworld --port=8080 | ||
``` | ||
|
||
### Viewing exported metrics | ||
|
||
This example is configured to export metrics via `debug` and `googlemanagedprometheus` exporters in the OpenTelemetry Collector. | ||
|
||
- The exported metrics from the `debug` exporter can be viewed on standard out through the logs explorer in GCP. | ||
- The exported metrics from `googlemanagedprometheus` can be viewed in [metrics explorer](https://cloud.google.com/monitoring/charts/metrics-selector). You can search for the metric named `function_counter_gmp` and it should be listed under the resource `Prometheus Target`. | ||
|
||
### Cleanup | ||
|
||
After you are done with the example you can follow these steps to clean up any Google Cloud Resources created when running this example: | ||
|
||
```shell | ||
# Delete the deployed function | ||
gcloud run services delete cloud-func-helloworld | ||
|
||
# Delete the artifact registry and all its contents | ||
gcloud artifacts repositories delete otlp-cloud-run --location=us-central1 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright 2024 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. | ||
*/ | ||
plugins { | ||
id 'java' | ||
id "com.github.johnrengelman.shadow" | ||
} | ||
|
||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar | ||
|
||
group 'org.example' | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
configurations { | ||
invoker | ||
} | ||
|
||
dependencies { | ||
implementation 'com.google.cloud.functions:functions-framework-api:1.0.4' | ||
implementation(libraries.opentelemetry_api) | ||
implementation(libraries.opentelemetry_sdk_metrics) | ||
|
||
// required by resource detection | ||
implementation(libraries.opentelemetry_autoconfigure_spi) | ||
// resource detection module | ||
implementation(libraries.opentelemetry_gcp_resources) | ||
|
||
implementation(libraries.opentelemetry_otlp_exporter) | ||
implementation(libraries.opentelemetry_logging_exporter) | ||
|
||
// For testing functions locally | ||
invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.1.1' | ||
} | ||
|
||
jar { | ||
manifest { | ||
doFirst { | ||
attributes 'Class-Path': files(configurations.runtimeClasspath).asPath | ||
} | ||
} | ||
} | ||
|
||
tasks.named('shadowJar', ShadowJar) { | ||
archivesBaseName = 'hello-world-function' | ||
archiveClassifier = '' | ||
archiveVersion = '' | ||
destinationDirectory.set(file('out/deployment/')) | ||
} | ||
|
||
// Task only used to test the function locally | ||
tasks.register('runFunction', JavaExec) { | ||
mainClass = 'com.google.cloud.functions.invoker.runner.Invoker' | ||
classpath(configurations.invoker) | ||
inputs.files(configurations.runtimeClasspath, sourceSets.main.output) | ||
args( | ||
'--target', project.findProperty('run.functionTarget'), | ||
'--port', project.findProperty('run.port') ?: 8080 | ||
) | ||
doFirst { | ||
args('--classpath', files(configurations.runtimeClasspath, sourceSets.main.output).asPath) | ||
} | ||
} | ||
|
||
test { | ||
useJUnitPlatform() | ||
} |
17 changes: 17 additions & 0 deletions
17
examples/otlpmetrics-function/collector-deployment/Dockerfile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright 2024 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. | ||
|
||
FROM otel/opentelemetry-collector-contrib:0.87.0 | ||
|
||
COPY collector-config.yaml /etc/otelcol-contrib/config.yaml |
43 changes: 43 additions & 0 deletions
43
examples/otlpmetrics-function/collector-deployment/collector-config.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Copyright 2024 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. | ||
|
||
receivers: | ||
otlp: | ||
protocols: | ||
grpc: | ||
http: | ||
|
||
processors: | ||
resourcedetection: | ||
detectors: [env, gcp] | ||
timeout: 2s | ||
override: false | ||
|
||
exporters: | ||
googlemanagedprometheus: | ||
debug: | ||
verbosity: detailed | ||
sampling_initial: 5 | ||
sampling_thereafter: 200 | ||
|
||
extensions: | ||
health_check: | ||
|
||
service: | ||
extensions: [health_check] | ||
pipelines: | ||
metrics: | ||
receivers: [otlp] | ||
processors: [resourcedetection] | ||
exporters: [debug, googlemanagedprometheus] |
55 changes: 55 additions & 0 deletions
55
...src/main/java/com/google/cloud/opentelemetry/examples/otlpmetricsfunction/HelloWorld.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
* Copyright 2024 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. | ||
*/ | ||
package com.google.cloud.opentelemetry.examples.otlpmetricsfunction; | ||
|
||
import com.google.cloud.functions.HttpFunction; | ||
import com.google.cloud.functions.HttpRequest; | ||
import com.google.cloud.functions.HttpResponse; | ||
import io.opentelemetry.api.metrics.LongCounter; | ||
import java.util.Random; | ||
|
||
public class HelloWorld implements HttpFunction { | ||
private static final OpenTelemetryConfig openTelemetryConfig = OpenTelemetryConfig.getInstance(); | ||
private static final LongCounter counter = | ||
openTelemetryConfig | ||
.getMeterProvider() | ||
.get("sample-function-library") | ||
.counterBuilder("function_counter_gmp") | ||
.setDescription("random counter") | ||
.build(); | ||
private static final Random random = new Random(); | ||
|
||
public HelloWorld() { | ||
super(); | ||
// Register a shutdown hook as soon as the function object is instantiated | ||
Runtime.getRuntime() | ||
.addShutdownHook( | ||
new Thread( | ||
() -> { | ||
System.out.println("Closing OpenTelemetry SDK"); | ||
openTelemetryConfig.closeSdk(); | ||
System.out.println("OpenTelemetry SDK closed"); | ||
})); | ||
} | ||
|
||
@Override | ||
public void service(HttpRequest request, HttpResponse response) throws Exception { | ||
System.out.println("received request: " + request.toString()); | ||
counter.add(random.nextInt(100)); | ||
response.getWriter().write("Hello, World\n"); | ||
System.out.println("Function exited"); | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
...java/com/google/cloud/opentelemetry/examples/otlpmetricsfunction/OpenTelemetryConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Copyright 2024 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. | ||
*/ | ||
package com.google.cloud.opentelemetry.examples.otlpmetricsfunction; | ||
|
||
import io.opentelemetry.api.metrics.MeterProvider; | ||
import io.opentelemetry.contrib.gcp.resource.GCPResourceProvider; | ||
import io.opentelemetry.exporter.logging.LoggingMetricExporter; | ||
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; | ||
import io.opentelemetry.sdk.OpenTelemetrySdk; | ||
import io.opentelemetry.sdk.metrics.SdkMeterProvider; | ||
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; | ||
import io.opentelemetry.sdk.resources.Resource; | ||
import java.time.Duration; | ||
|
||
/** | ||
* A singleton class representing the OpenTelemetry instance that can be used to instrument the | ||
* application. | ||
*/ | ||
public final class OpenTelemetryConfig { | ||
private static final OpenTelemetryConfig INSTANCE = new OpenTelemetryConfig(); | ||
private static final int METRIC_EXPORT_DURATION_MILLIS = 10000; | ||
private final OpenTelemetrySdk openTelemetry; | ||
|
||
// prevent object creation | ||
private OpenTelemetryConfig() { | ||
this.openTelemetry = initOpenTelemetry(); | ||
} | ||
|
||
public static OpenTelemetryConfig getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
public MeterProvider getMeterProvider() { | ||
return this.openTelemetry.getMeterProvider(); | ||
} | ||
|
||
/** Closes the OpenTelemetry SDK instance, exporting any pending metrics. */ | ||
public void closeSdk() { | ||
openTelemetry.close(); | ||
} | ||
|
||
private OpenTelemetrySdk initOpenTelemetry() { | ||
// Enable proper resource detection within the application | ||
// This is used for the logging exporter. | ||
GCPResourceProvider resourceProvider = new GCPResourceProvider(); | ||
Resource resource = Resource.getDefault().merge(resourceProvider.createResource(null)); | ||
|
||
return OpenTelemetrySdk.builder() | ||
.setMeterProvider( | ||
SdkMeterProvider.builder() | ||
.setResource(resource) | ||
.registerMetricReader( | ||
PeriodicMetricReader.builder(LoggingMetricExporter.create()) | ||
.setInterval(Duration.ofMillis(METRIC_EXPORT_DURATION_MILLIS)) | ||
.build()) | ||
.registerMetricReader( | ||
PeriodicMetricReader.builder(OtlpGrpcMetricExporter.getDefault()) | ||
.setInterval(Duration.ofMillis(METRIC_EXPORT_DURATION_MILLIS)) | ||
.build()) | ||
.build()) | ||
.buildAndRegisterGlobal(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters