Google Cloud Run

Prerequisites

  • A Google Cloud project with Cloud Run and Artifact Registry enabled
  • gcloud CLI authenticated and configured
  • A containerised application (Dockerfile)
  • Node.js 18+ for the Node section; .NET 6+ for the .NET section

Features Supported

CapabilityNode.js.NET
Traces
Metrics
App Logs
Custom Logs
Profiling
Node.js on Cloud Run
.NET on Cloud Run
Python on Cloud Run

1 Install the APM package

npm install @middleware.io/node-apm --save

Ensure this package is listed in package.json so your container build installs it.

2 Initialise the tracker before your app code

You must initialise the tracker before loading any other modules so auto‑instrumentation can hook framework/runtime internals.

  • JavaScript (CommonJS) via preload file + --require Create instrumentation.js:
    // instrumentation.js
    const tracker = require('@middleware.io/node-apm');
    
    tracker.track({
      serviceName: '<MW_SERVICE_NAME>',
      accessToken: '<MW_API_KEY>',
      target: 'https://<MW_UID>.middleware.io:443',
      // Optional extras
      projectName: '<MW_PROJECT_NAME>',
    });
    Start your app with Node’s preload:
    node --require ./instrumentation.js app.js
    If your app is ESM‑only, --require won’t work. Use the ESM approach below.
  • JavaScript (ESM) via --import Create instrumentation.mjs:
    // instrumentation.mjs
    import * as tracker from '@middleware.io/node-apm';
    
    tracker.track({
      serviceName: '<MW_SERVICE_NAME>',
      accessToken: '<MW_API_KEY>',
      target: 'https://<MW_UID>.middleware.io:443',
      projectName: '<MW_PROJECT_NAME>',
    });
    Run using Node’s ESM import hook (Node 18+):
    node --import ./instrumentation.mjs app.mjs
  • TypeScript Create instrumentation.ts:
    // instrumentation.ts
    import * as tracker from '@middleware.io/node-apm';
    
    tracker.track({
      serviceName: '<MW_SERVICE_NAME>',
      accessToken: '<MW_API_KEY>',
      target: 'https://<MW_UID>.middleware.io:443',
      projectName: '<MW_PROJECT_NAME>',
    });
    Dev / quick start (ts-node):
    npx ts-node --require ./instrumentation.ts app.ts
    ESM TypeScript (optional):
    node --loader ts-node/esm --import ./instrumentation.ts app.ts
    Production best practice: compile to JS and run with the JS instructions.
    npx tsc
    node --require ./instrumentation.js dist/app.js

Alternate initialisation: you may place the tracker code at the very top of your app’s entry file (before any other import/require). Using a preload file is recommended as it avoids accidental reordering.

3 Cloud Run environment variables

Add the following env vars to your Cloud Run service (Console → Cloud Run → Service → Edit & deploy → Variables & Secrets):

OTEL_NODE_RESOURCE_DETECTORS=all

Reduce missing spans in serverless:

OTEL_BSP_SCHEDULE_DELAY=500

Lower values flush more frequently and can reduce data loss at shutdown (modestly higher network cost).

You can also gracefully shut down programmatically (next section) to ensure final export on SIGTERM.

4 Graceful Shutdown (recommended)

Add a shutdown handler so Cloud Run’s SIGTERM can trigger a final export before the 10‑second termination window.

// main app (Node.js)
const tracker = require('@middleware.io/node-apm');

// If not already initialised via preload:
// tracker.track({ serviceName: '<MW_SERVICE_NAME>', accessToken: '<MW_API_KEY>', target: '<MW_TARGET_URL>' });

process.on('SIGTERM', async () => {
  console.log('SIGTERM received -- flushing Middleware telemetry...');
  try {
    await tracker.sdkShutdown();
  } finally {
    process.exit(0);
  }
});

On some platforms you may also wish to listen for SIGINT (manual stop) in local/dev.

5 Custom Logs & Error Stacks (optional)

// anywhere in your code
const tracker = require('@middleware.io/node-apm');

tracker.info('Info sample');
tracker.warn('Warning sample');
tracker.debug('Debugging sample');
tracker.error('Error sample');

// Record an Error object and stack
try {
  throw new Error('oh error!');
} catch (e) {
  tracker.errorRecord(e);
}

1 Install the package

dotnet add package MW.APM

For Visual Studio, go to Tools → NuGet Package Manager → Manage NuGet Packages for Solution → Browse → MW.APM → Install

2 Wire up Instrumentation & Logging

In Program.cs:

var builder = WebApplication.CreateBuilder(args);

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddEnvironmentVariables()
    .Build();

builder.Services.ConfigureMWInstrumentation(configuration);

builder.Logging.AddConfiguration(configuration.GetSection("Logging"));
builder.Logging.AddConsole();
builder.Logging.SetMinimumLevel(LogLevel.Debug);

var app = builder.Build();

// After app creation (so MW can capture logs)
Logger.Init(app.Services.GetRequiredService<ILoggerFactory>());

app.MapGet("/health", () => Results.Ok("ok"));

app.Run();

3 Configure Your Middleware Account Settings

appsettings.json:

{
  "MW": {
    "ApiKey": "<MW_API_KEY>",
    "TargetURL": "https://<MW_UID>.middleware.io:443",
    "ServiceName": "<MW_SERVICE_NAME>",
    "ProjectName": "<MW_PROJECT_NAME>",

    "ConsoleExporter": "true",
    "ExcludeLinks": "[\"/health\"]",

    // Collectors (toggle as needed)
    "ApmCollectMetrics": "true",
    "ApmCollectTraces": "true",
    "ApmCollectLogs": "true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

This is a one‑time configuration. Each container that starts on Cloud Run will initialise the .NET instrumentation.

1 Add middleware-io to requirements.txt

middleware-io>=2.4.1
setuptools

This ensures the package is installed when your Cloud Run container builds.

2 Setup Options

Auto-instrumentation
Manual-instrumentation

Auto instrumentation allows you to monitor your Python application without modifying the application code. This can be achieved by setting environment variables that configure the application with Middleware Application Performance Monitoring (APM) tool.

Setup Virtual Environment

python -m venv myenv
source myenv/bin/activate

Install Requirements To install requirements mentioned in the file requirements.txt run the command in your terminal:

pip install -r requirements.txt

Install OpenTelemetry automatic instrumentation libraries: Run the command to install instrumentation library:

middleware-bootstrap -a install

The middleware-bootstrap -a install command reads through the list of packages installed in your active site-packages folder, and installs the corresponding instrumentation libraries for these packages, if applicable. For example, if you already installed the flask package, running middleware-bootstrap -a install will install opentelemetry-instrumentation-flask for you. The Middleware Python agent will use monkey patching to modify functions in these libraries at runtime.

Ensure library is installed properly with command:

pip list | grep -i flask

Flask
opentelemetry-instrumentation-flask

For Containerized Application add command in dockerfile:

RUN middleware-bootstrap -a install

Example:

You can set the following environment variables in your shell to auto instrument:

export MW_API_KEY='<MW_API_KEY>'
export MW_TARGET='https://<MW_UID>.middleware.io:443'
export MW_SERVICE_NAME='MyFlaskServer'
middleware-run python app.py

If you prefer more control and want to integrate APM directly into your application, you can use a middleware function like mw_tracker. This method requires adding a specific function call in your application's code. Set these environment variables in your Cloud Run service configuration or Dockerfile:

MW_TRACKER=True

Then, initialize in your code with:

Example: Using mw_tracker Function from Middleware

from flask import Flask
# Import the mw_tracker from middleware to your app
from middleware import mw_tracker, MWOptions, record_exception, DETECT_GCP

 mw_tracker(
     MWOptions(
         access_token="<MW_API_KEY>",
         target="https://<MW_UID>.middleware.io:443",
         console_exporter=True,
         debug_log_file=True,
         service_name="MyPythonServer",
         otel_propagators = "b3,tracecontext",
         custom_resource_attributes="call_id=12345678, request_id=987654321",
         detectors=[DETECT_GCP]
     )
 )

app = Flask(__name__)

@app.route('/')
def index():
    return "Hello, World!"

if __name__ == "__main__":
    app.run()

For more advanced configuration of MWOptions check out this list of all possible options here.

3 Add Custom Instrumentation (Optional)

If you need to add custom spans or attributes, see Python APM configuration.

Troubleshooting If you encounter any issues, visit Python troubleshooting.

Troubleshooting:

  • Nothing appears in Traces
    • Ensure the tracker initialises before any other imports.
    • Check that the container actually runs with --require / --import (print process.execArgv).
    • Confirm Node.js 18+ in the container (node --version).
  • ESM errors with --require → use the ESM path (--import) or move initialisation to the entry file’s first line.
  • TypeScript only works locally → compile to JS in CI/CD and run the JS entry in Cloud Run.
  • Spans missing on shutdown → set OTEL_BSP_SCHEDULE_DELAY=500 and add the SIGTERM handler that calls tracker.sdkShutdown().
  • Networking: ensure outbound egress to <MW_TARGET_URL> is allowed by your VPC/Egress settings.

Need assistance or want to learn more about Middleware? Contact our support team at [email protected] or join our Slack channel.