Sending Logs from Google Cloud Run to OpenObserve


What You’ll Learn
This instructional blog covers how to send structured logs from your Google Cloud Run app directly to OpenObserve using simple HTTP requests and with just a few lines of code. We'll cover:
When you deploy a service on Google Cloud Run, logs are automatically collected and sent to Cloud Logging. You can see stdout, errors, and request logs in the Logs Explorer.
However, while Cloud Logging works well for basic needs, as your observability requirements grow, it can become a bottleneck.
You may start to hit limitations when you try to:
This is where OpenObserve helps. It’s fast, simple to use, and much more cost-efficient, especially for larger volumes and longer retention. With OpenObserve, you can unify your logs, metrics, and traces, sending data directly from your app using an HTTP API.
Login to your OpenObserve dashboard and collect the following:
URL: Your OpenObserve URL (like https://api.openobserve.ai)
Organization: Your organization name.
Found in the top-right of your OpenObserve UI
Authorization token: Get your Authorization token from the Data Sources page:
You’ll pass these to your app using environment variables in Cloud Run.
Modify your existing app by adding a small function to send logs via HTTP.
import requests
import json
import base64
import os
from datetime import datetime
def send_log(message):
try:
auth = os.environ['OPENOBSERVE_AUTH_KEY']
response = requests.post(
f"{os.environ['OPENOBSERVE_URL']}/api/{os.environ['OPENOBSERVE_ORG']}/{os.environ['OPENOBSERVE_STREAM']}/_json",
json=[{
"timestamp": datetime.now().isoformat(),
"message": message,
"level": "info"
}],
headers={
"Authorization": f"Basic {auth}",
"Content-Type": "application/json"
}
)
print(f"Log sent. Status: {response.status_code}, Response: {response.text}",flush=True)
except Exception as e:
print(f"OpenObserve error: {e}")
You can call this logging function from any route in your app, for example:
@app.route('/')
def hello():
send_log('Homepage visited')
return 'Hello World'
const axios = require('axios');
async function sendLog(message) {
try {
await axios.post(
`${process.env.OPENOBSERVE_URL}/api/${process.env.OPENOBSERVE_ORG}/${process.env.OPENOBSERVE_STREAM}/_json`,
[{
timestamp: new Date().toISOString(),
message: message,
level: 'info'
}],
{
headers: {
'Authorization': `Basic ${process.env.OPENOBSERVE_AUTH_KEY}`,
'Content-Type': 'application/json'
}
}
);
} catch (error) {
console.error('OpenObserve error:', error.message);
}
}
Use it inside your route:
app.get('/', (req, res) => {
sendLog('Homepage visited');
res.send('Hello World');
});
If you’d prefer to test the integration before changing your own application, you can use this sample project: cloudrun-openobserve-demo (GitHub)
It contains a minimal Cloud Run-compatible app with the logging code already set up. Just deploy it and provide the required environment variables (covered in Step 3) during setup.
Go to the Cloud Run Console
Click your service name
Click “Edit & Deploy New Revision”
Scroll to “Variables & Secrets” → Environment Variables
Add the following 4 variables:
Variable Name | Value |
---|---|
OPENOBSERVE_URL | https://api.openobserve.ai |
OPENOBSERVE_ORG | your organization name |
OPENOBSERVE_STREAM | the stream name you would like to have |
OPENOBSERVE_AUTH_KEY | the API key from OpenObserve |
Click Deploy to roll out the changes.
Hello World
, in your browser.{
"timestamp": "2025-07-24T14:00:00Z",
"message": "Homepage visited",
"level": "info"
}
Logs may take a few seconds to appear in OpenObserve. If you don’t see them, double-check your stream name and org.
That’s it! Your Cloud Run app now streams structured logs directly to OpenObserve , giving you richer filtering, and better cost control.
Logs not appearing in OpenObserve?
Here are a few things to check:
Stream or Organization Name Typos Double-check that the values for OPENOBSERVE_STREAM and OPENOBSERVE_ORG exactly match what’s configured in OpenObserve.
Cloud Run Logs Show 404 or 401 A 404 typically means the stream path is incorrect. A 401 usually means the API key or auth format is invalid.
No Response from Log Sender Function Add flush=True in the print() calls to ensure logs appear in Cloud Run’s stdout logs:
print(f"Log sent. Status: {response.status_code}", flush=True)
curl -X POST \
-H "Authorization: Basic YOUR_AUTH_KEY" \
-H "Content-Type: application/json" \
-d '[{"message": "test log"}]' \
https://YOUR_OPENOBSERVE_URL/api/YOUR_ORG/YOUR_STREAM/_json
By streaming logs directly to OpenObserve, you're no longer limited by Cloud Logging’s cost or search performance. This setup supports:
While this guide shows how to send logs directly from a Cloud Run service using simple HTTP calls, there’s another approach worth exploring, especially if you want to forward logs from multiple GCP services like GKE, Cloud Functions, or even Cloud Load Balancers.
You can use Google Cloud’s native logging pipeline (Cloud Logging → Pub/Sub) to stream logs into OpenObserve without modifying your app code.
→ Check out our guide on forwarding GCP logs to OpenObserve via Pub/Sub
Chaitanya Sistla is a Principal Solutions Architect with 16X certifications across Cloud, Data, DevOps, and Cybersecurity. Leveraging extensive startup experience and a focus on MLOps, Chaitanya excels at designing scalable, innovative solutions that drive operational excellence and business transformation.