Create GCP Cloud Logging Metrics

The gcp:logging/metric:Metric resource, part of the Pulumi GCP provider, defines logs-based metrics that extract values from log entries and generate time-series data for monitoring. This guide focuses on four capabilities: counter metrics with filters, label extraction for dimensional data, distribution metrics with histograms, and bucket scoping.

Logs-based metrics process entries from Cloud Logging and may reference specific log buckets. The examples are intentionally small. Combine them with your own log filters, monitoring dashboards, and alerting policies.

Count log entries matching a filter

Most logs-based metrics start by counting how many log entries match a filter, such as error-level messages from a specific service.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const loggingMetric = new gcp.logging.Metric("logging_metric", {
    name: "my-(custom)/metric",
    filter: "resource.type=gae_app AND severity>=ERROR",
    metricDescriptor: {
        metricKind: "DELTA",
        valueType: "INT64",
    },
});
import pulumi
import pulumi_gcp as gcp

logging_metric = gcp.logging.Metric("logging_metric",
    name="my-(custom)/metric",
    filter="resource.type=gae_app AND severity>=ERROR",
    metric_descriptor={
        "metric_kind": "DELTA",
        "value_type": "INT64",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/logging"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := logging.NewMetric(ctx, "logging_metric", &logging.MetricArgs{
			Name:   pulumi.String("my-(custom)/metric"),
			Filter: pulumi.String("resource.type=gae_app AND severity>=ERROR"),
			MetricDescriptor: &logging.MetricMetricDescriptorArgs{
				MetricKind: pulumi.String("DELTA"),
				ValueType:  pulumi.String("INT64"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var loggingMetric = new Gcp.Logging.Metric("logging_metric", new()
    {
        Name = "my-(custom)/metric",
        Filter = "resource.type=gae_app AND severity>=ERROR",
        MetricDescriptor = new Gcp.Logging.Inputs.MetricMetricDescriptorArgs
        {
            MetricKind = "DELTA",
            ValueType = "INT64",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.Metric;
import com.pulumi.gcp.logging.MetricArgs;
import com.pulumi.gcp.logging.inputs.MetricMetricDescriptorArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var loggingMetric = new Metric("loggingMetric", MetricArgs.builder()
            .name("my-(custom)/metric")
            .filter("resource.type=gae_app AND severity>=ERROR")
            .metricDescriptor(MetricMetricDescriptorArgs.builder()
                .metricKind("DELTA")
                .valueType("INT64")
                .build())
            .build());

    }
}
resources:
  loggingMetric:
    type: gcp:logging:Metric
    name: logging_metric
    properties:
      name: my-(custom)/metric
      filter: resource.type=gae_app AND severity>=ERROR
      metricDescriptor:
        metricKind: DELTA
        valueType: INT64

The filter property uses Cloud Logging’s advanced query syntax to select log entries. The metricDescriptor defines what kind of metric you’re creating: DELTA tracks changes between measurements, while INT64 stores the count as an integer. This configuration counts matching log entries without extracting values or adding dimensions.

Add dimensions to counters with labels

When you need to break down counts by dimensions like request type or user ID, labels extract values from log fields and attach them as metric dimensions.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const loggingMetric = new gcp.logging.Metric("logging_metric", {
    name: "my-(custom)/metric",
    filter: "resource.type=gae_app AND severity>=ERROR",
    metricDescriptor: {
        metricKind: "DELTA",
        valueType: "INT64",
        labels: [{
            key: "mass",
            valueType: "STRING",
            description: "amount of matter",
        }],
    },
    labelExtractors: {
        mass: "EXTRACT(jsonPayload.request)",
    },
});
import pulumi
import pulumi_gcp as gcp

logging_metric = gcp.logging.Metric("logging_metric",
    name="my-(custom)/metric",
    filter="resource.type=gae_app AND severity>=ERROR",
    metric_descriptor={
        "metric_kind": "DELTA",
        "value_type": "INT64",
        "labels": [{
            "key": "mass",
            "value_type": "STRING",
            "description": "amount of matter",
        }],
    },
    label_extractors={
        "mass": "EXTRACT(jsonPayload.request)",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/logging"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := logging.NewMetric(ctx, "logging_metric", &logging.MetricArgs{
			Name:   pulumi.String("my-(custom)/metric"),
			Filter: pulumi.String("resource.type=gae_app AND severity>=ERROR"),
			MetricDescriptor: &logging.MetricMetricDescriptorArgs{
				MetricKind: pulumi.String("DELTA"),
				ValueType:  pulumi.String("INT64"),
				Labels: logging.MetricMetricDescriptorLabelArray{
					&logging.MetricMetricDescriptorLabelArgs{
						Key:         pulumi.String("mass"),
						ValueType:   pulumi.String("STRING"),
						Description: pulumi.String("amount of matter"),
					},
				},
			},
			LabelExtractors: pulumi.StringMap{
				"mass": pulumi.String("EXTRACT(jsonPayload.request)"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var loggingMetric = new Gcp.Logging.Metric("logging_metric", new()
    {
        Name = "my-(custom)/metric",
        Filter = "resource.type=gae_app AND severity>=ERROR",
        MetricDescriptor = new Gcp.Logging.Inputs.MetricMetricDescriptorArgs
        {
            MetricKind = "DELTA",
            ValueType = "INT64",
            Labels = new[]
            {
                new Gcp.Logging.Inputs.MetricMetricDescriptorLabelArgs
                {
                    Key = "mass",
                    ValueType = "STRING",
                    Description = "amount of matter",
                },
            },
        },
        LabelExtractors = 
        {
            { "mass", "EXTRACT(jsonPayload.request)" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.Metric;
import com.pulumi.gcp.logging.MetricArgs;
import com.pulumi.gcp.logging.inputs.MetricMetricDescriptorArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var loggingMetric = new Metric("loggingMetric", MetricArgs.builder()
            .name("my-(custom)/metric")
            .filter("resource.type=gae_app AND severity>=ERROR")
            .metricDescriptor(MetricMetricDescriptorArgs.builder()
                .metricKind("DELTA")
                .valueType("INT64")
                .labels(MetricMetricDescriptorLabelArgs.builder()
                    .key("mass")
                    .valueType("STRING")
                    .description("amount of matter")
                    .build())
                .build())
            .labelExtractors(Map.of("mass", "EXTRACT(jsonPayload.request)"))
            .build());

    }
}
resources:
  loggingMetric:
    type: gcp:logging:Metric
    name: logging_metric
    properties:
      name: my-(custom)/metric
      filter: resource.type=gae_app AND severity>=ERROR
      metricDescriptor:
        metricKind: DELTA
        valueType: INT64
        labels:
          - key: mass
            valueType: STRING
            description: amount of matter
      labelExtractors:
        mass: EXTRACT(jsonPayload.request)

The labels array in metricDescriptor defines dimensions for your metric. Each label needs a key, valueType, and optional description. The labelExtractors map connects label keys to EXTRACT expressions that pull values from log entry fields. Here, the “mass” label extracts data from jsonPayload.request, letting you group counts by that field’s values.

Create distribution metrics with histograms

Applications that track value distributions (like request latencies or payload sizes) use distribution metrics to record statistics and histograms.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const loggingMetric = new gcp.logging.Metric("logging_metric", {
    name: "my-(custom)/metric",
    filter: "resource.type=gae_app AND severity>=ERROR",
    metricDescriptor: {
        metricKind: "DELTA",
        valueType: "DISTRIBUTION",
        unit: "1",
        labels: [
            {
                key: "mass",
                valueType: "STRING",
                description: "amount of matter",
            },
            {
                key: "sku",
                valueType: "INT64",
                description: "Identifying number for item",
            },
        ],
        displayName: "My metric",
    },
    valueExtractor: "EXTRACT(jsonPayload.request)",
    labelExtractors: {
        mass: "EXTRACT(jsonPayload.request)",
        sku: "EXTRACT(jsonPayload.id)",
    },
    bucketOptions: {
        linearBuckets: {
            numFiniteBuckets: 3,
            width: 1,
            offset: 1,
        },
    },
});
import pulumi
import pulumi_gcp as gcp

logging_metric = gcp.logging.Metric("logging_metric",
    name="my-(custom)/metric",
    filter="resource.type=gae_app AND severity>=ERROR",
    metric_descriptor={
        "metric_kind": "DELTA",
        "value_type": "DISTRIBUTION",
        "unit": "1",
        "labels": [
            {
                "key": "mass",
                "value_type": "STRING",
                "description": "amount of matter",
            },
            {
                "key": "sku",
                "value_type": "INT64",
                "description": "Identifying number for item",
            },
        ],
        "display_name": "My metric",
    },
    value_extractor="EXTRACT(jsonPayload.request)",
    label_extractors={
        "mass": "EXTRACT(jsonPayload.request)",
        "sku": "EXTRACT(jsonPayload.id)",
    },
    bucket_options={
        "linear_buckets": {
            "num_finite_buckets": 3,
            "width": 1,
            "offset": 1,
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/logging"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := logging.NewMetric(ctx, "logging_metric", &logging.MetricArgs{
			Name:   pulumi.String("my-(custom)/metric"),
			Filter: pulumi.String("resource.type=gae_app AND severity>=ERROR"),
			MetricDescriptor: &logging.MetricMetricDescriptorArgs{
				MetricKind: pulumi.String("DELTA"),
				ValueType:  pulumi.String("DISTRIBUTION"),
				Unit:       pulumi.String("1"),
				Labels: logging.MetricMetricDescriptorLabelArray{
					&logging.MetricMetricDescriptorLabelArgs{
						Key:         pulumi.String("mass"),
						ValueType:   pulumi.String("STRING"),
						Description: pulumi.String("amount of matter"),
					},
					&logging.MetricMetricDescriptorLabelArgs{
						Key:         pulumi.String("sku"),
						ValueType:   pulumi.String("INT64"),
						Description: pulumi.String("Identifying number for item"),
					},
				},
				DisplayName: pulumi.String("My metric"),
			},
			ValueExtractor: pulumi.String("EXTRACT(jsonPayload.request)"),
			LabelExtractors: pulumi.StringMap{
				"mass": pulumi.String("EXTRACT(jsonPayload.request)"),
				"sku":  pulumi.String("EXTRACT(jsonPayload.id)"),
			},
			BucketOptions: &logging.MetricBucketOptionsArgs{
				LinearBuckets: &logging.MetricBucketOptionsLinearBucketsArgs{
					NumFiniteBuckets: pulumi.Int(3),
					Width:            pulumi.Float64(1),
					Offset:           pulumi.Float64(1),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var loggingMetric = new Gcp.Logging.Metric("logging_metric", new()
    {
        Name = "my-(custom)/metric",
        Filter = "resource.type=gae_app AND severity>=ERROR",
        MetricDescriptor = new Gcp.Logging.Inputs.MetricMetricDescriptorArgs
        {
            MetricKind = "DELTA",
            ValueType = "DISTRIBUTION",
            Unit = "1",
            Labels = new[]
            {
                new Gcp.Logging.Inputs.MetricMetricDescriptorLabelArgs
                {
                    Key = "mass",
                    ValueType = "STRING",
                    Description = "amount of matter",
                },
                new Gcp.Logging.Inputs.MetricMetricDescriptorLabelArgs
                {
                    Key = "sku",
                    ValueType = "INT64",
                    Description = "Identifying number for item",
                },
            },
            DisplayName = "My metric",
        },
        ValueExtractor = "EXTRACT(jsonPayload.request)",
        LabelExtractors = 
        {
            { "mass", "EXTRACT(jsonPayload.request)" },
            { "sku", "EXTRACT(jsonPayload.id)" },
        },
        BucketOptions = new Gcp.Logging.Inputs.MetricBucketOptionsArgs
        {
            LinearBuckets = new Gcp.Logging.Inputs.MetricBucketOptionsLinearBucketsArgs
            {
                NumFiniteBuckets = 3,
                Width = 1,
                Offset = 1,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.Metric;
import com.pulumi.gcp.logging.MetricArgs;
import com.pulumi.gcp.logging.inputs.MetricMetricDescriptorArgs;
import com.pulumi.gcp.logging.inputs.MetricBucketOptionsArgs;
import com.pulumi.gcp.logging.inputs.MetricBucketOptionsLinearBucketsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var loggingMetric = new Metric("loggingMetric", MetricArgs.builder()
            .name("my-(custom)/metric")
            .filter("resource.type=gae_app AND severity>=ERROR")
            .metricDescriptor(MetricMetricDescriptorArgs.builder()
                .metricKind("DELTA")
                .valueType("DISTRIBUTION")
                .unit("1")
                .labels(                
                    MetricMetricDescriptorLabelArgs.builder()
                        .key("mass")
                        .valueType("STRING")
                        .description("amount of matter")
                        .build(),
                    MetricMetricDescriptorLabelArgs.builder()
                        .key("sku")
                        .valueType("INT64")
                        .description("Identifying number for item")
                        .build())
                .displayName("My metric")
                .build())
            .valueExtractor("EXTRACT(jsonPayload.request)")
            .labelExtractors(Map.ofEntries(
                Map.entry("mass", "EXTRACT(jsonPayload.request)"),
                Map.entry("sku", "EXTRACT(jsonPayload.id)")
            ))
            .bucketOptions(MetricBucketOptionsArgs.builder()
                .linearBuckets(MetricBucketOptionsLinearBucketsArgs.builder()
                    .numFiniteBuckets(3)
                    .width(1.0)
                    .offset(1.0)
                    .build())
                .build())
            .build());

    }
}
resources:
  loggingMetric:
    type: gcp:logging:Metric
    name: logging_metric
    properties:
      name: my-(custom)/metric
      filter: resource.type=gae_app AND severity>=ERROR
      metricDescriptor:
        metricKind: DELTA
        valueType: DISTRIBUTION
        unit: '1'
        labels:
          - key: mass
            valueType: STRING
            description: amount of matter
          - key: sku
            valueType: INT64
            description: Identifying number for item
        displayName: My metric
      valueExtractor: EXTRACT(jsonPayload.request)
      labelExtractors:
        mass: EXTRACT(jsonPayload.request)
        sku: EXTRACT(jsonPayload.id)
      bucketOptions:
        linearBuckets:
          numFiniteBuckets: 3
          width: 1
          offset: 1

Distribution metrics require a valueExtractor to pull numeric values from log entries. The bucketOptions property defines histogram boundaries: linearBuckets creates evenly-spaced buckets starting at offset, with specified width and count. The metricDescriptor’s valueType must be DISTRIBUTION, and you can add labels just like counter metrics. The displayName appears in Cloud Monitoring dashboards.

Scope metrics to specific log buckets

Organizations that route logs to different buckets for retention or access control can create metrics that only process entries from a specific bucket.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const loggingMetric = new gcp.logging.ProjectBucketConfig("logging_metric", {
    location: "global",
    project: "my-project-name",
    bucketId: "_Default",
});
const loggingMetricMetric = new gcp.logging.Metric("logging_metric", {
    name: "my-(custom)/metric",
    filter: "resource.type=gae_app AND severity>=ERROR",
    bucketName: loggingMetric.name,
});
import pulumi
import pulumi_gcp as gcp

logging_metric = gcp.logging.ProjectBucketConfig("logging_metric",
    location="global",
    project="my-project-name",
    bucket_id="_Default")
logging_metric_metric = gcp.logging.Metric("logging_metric",
    name="my-(custom)/metric",
    filter="resource.type=gae_app AND severity>=ERROR",
    bucket_name=logging_metric.name)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/logging"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		loggingMetric, err := logging.NewProjectBucketConfig(ctx, "logging_metric", &logging.ProjectBucketConfigArgs{
			Location: pulumi.String("global"),
			Project:  pulumi.String("my-project-name"),
			BucketId: pulumi.String("_Default"),
		})
		if err != nil {
			return err
		}
		_, err = logging.NewMetric(ctx, "logging_metric", &logging.MetricArgs{
			Name:       pulumi.String("my-(custom)/metric"),
			Filter:     pulumi.String("resource.type=gae_app AND severity>=ERROR"),
			BucketName: loggingMetric.Name,
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var loggingMetric = new Gcp.Logging.ProjectBucketConfig("logging_metric", new()
    {
        Location = "global",
        Project = "my-project-name",
        BucketId = "_Default",
    });

    var loggingMetricMetric = new Gcp.Logging.Metric("logging_metric", new()
    {
        Name = "my-(custom)/metric",
        Filter = "resource.type=gae_app AND severity>=ERROR",
        BucketName = loggingMetric.Name,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.ProjectBucketConfig;
import com.pulumi.gcp.logging.ProjectBucketConfigArgs;
import com.pulumi.gcp.logging.Metric;
import com.pulumi.gcp.logging.MetricArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var loggingMetric = new ProjectBucketConfig("loggingMetric", ProjectBucketConfigArgs.builder()
            .location("global")
            .project("my-project-name")
            .bucketId("_Default")
            .build());

        var loggingMetricMetric = new Metric("loggingMetricMetric", MetricArgs.builder()
            .name("my-(custom)/metric")
            .filter("resource.type=gae_app AND severity>=ERROR")
            .bucketName(loggingMetric.name())
            .build());

    }
}
resources:
  loggingMetric:
    type: gcp:logging:ProjectBucketConfig
    name: logging_metric
    properties:
      location: global
      project: my-project-name
      bucketId: _Default
  loggingMetricMetric:
    type: gcp:logging:Metric
    name: logging_metric
    properties:
      name: my-(custom)/metric
      filter: resource.type=gae_app AND severity>=ERROR
      bucketName: ${loggingMetric.name}

The bucketName property references a ProjectBucketConfig resource, limiting the metric to logs in that bucket. This is useful when you’ve configured log routing and want metrics that only process specific log streams. The bucket must exist in the same project as the metric.

Disable metrics without deleting them

When troubleshooting or managing costs, you can temporarily stop a metric from generating data points without removing its configuration.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const loggingMetric = new gcp.logging.Metric("logging_metric", {
    name: "my-(custom)/metric",
    filter: "resource.type=gae_app AND severity>=ERROR",
    metricDescriptor: {
        metricKind: "DELTA",
        valueType: "INT64",
    },
    disabled: true,
});
import pulumi
import pulumi_gcp as gcp

logging_metric = gcp.logging.Metric("logging_metric",
    name="my-(custom)/metric",
    filter="resource.type=gae_app AND severity>=ERROR",
    metric_descriptor={
        "metric_kind": "DELTA",
        "value_type": "INT64",
    },
    disabled=True)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/logging"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := logging.NewMetric(ctx, "logging_metric", &logging.MetricArgs{
			Name:   pulumi.String("my-(custom)/metric"),
			Filter: pulumi.String("resource.type=gae_app AND severity>=ERROR"),
			MetricDescriptor: &logging.MetricMetricDescriptorArgs{
				MetricKind: pulumi.String("DELTA"),
				ValueType:  pulumi.String("INT64"),
			},
			Disabled: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var loggingMetric = new Gcp.Logging.Metric("logging_metric", new()
    {
        Name = "my-(custom)/metric",
        Filter = "resource.type=gae_app AND severity>=ERROR",
        MetricDescriptor = new Gcp.Logging.Inputs.MetricMetricDescriptorArgs
        {
            MetricKind = "DELTA",
            ValueType = "INT64",
        },
        Disabled = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.logging.Metric;
import com.pulumi.gcp.logging.MetricArgs;
import com.pulumi.gcp.logging.inputs.MetricMetricDescriptorArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var loggingMetric = new Metric("loggingMetric", MetricArgs.builder()
            .name("my-(custom)/metric")
            .filter("resource.type=gae_app AND severity>=ERROR")
            .metricDescriptor(MetricMetricDescriptorArgs.builder()
                .metricKind("DELTA")
                .valueType("INT64")
                .build())
            .disabled(true)
            .build());

    }
}
resources:
  loggingMetric:
    type: gcp:logging:Metric
    name: logging_metric
    properties:
      name: my-(custom)/metric
      filter: resource.type=gae_app AND severity>=ERROR
      metricDescriptor:
        metricKind: DELTA
        valueType: INT64
      disabled: true

Setting disabled to true stops the metric from processing log entries and generating data points. The metric configuration remains intact, so you can re-enable it by setting disabled to false. This is useful for temporarily pausing expensive metrics or debugging metric behavior.

Beyond these examples

These snippets focus on specific metric-level features: counter and distribution metric types, label extraction and histogram configuration, and bucket scoping and metric lifecycle. They’re intentionally minimal rather than full monitoring solutions.

The examples assume pre-existing infrastructure such as a GCP project with Cloud Logging enabled, and log buckets for bucket-scoped metrics. They focus on configuring the metric rather than provisioning the logging infrastructure around it.

To keep things focused, common metric patterns are omitted, including:

  • Exponential and explicit bucket configurations
  • REGEXP_EXTRACT for complex field parsing
  • Metric descriptor units and display names
  • Integration with Cloud Monitoring dashboards and alerts

These omissions are intentional: the goal is to illustrate how each metric feature is wired, not provide drop-in monitoring modules. See the Logging Metric resource reference for all available configuration options.

Let's create GCP Cloud Logging Metrics

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Metric Types & Configuration
What's the difference between distribution and counter metrics?
Counter metrics use INT64 value type and simply count log entries matching your filter. Distribution metrics use DISTRIBUTION value type to extract values from logs and create histograms, requiring both valueExtractor and bucketOptions to be configured.
What happens if I don't specify a metricDescriptor?
The metric defaults to a counter with DELTA metric kind, INT64 value type, no labels, and unit "1". This configuration counts the number of log entries matching your filter expression.
How do I temporarily disable a metric without deleting it?
Set disabled to true. The metric stops generating data points but remains configured for future use.
Value & Label Extraction
When do I need to use valueExtractor?
You must use valueExtractor when creating distribution metrics (DISTRIBUTION value type). It supports two functions: EXTRACT(field) to extract a log field directly, or REGEXP_EXTRACT(field, regex) to extract using a regular expression with exactly one capture group.
Why is my REGEXP_EXTRACT failing with a regex error?
Your regex must include exactly one capture group. The field value is converted to a string before applying the regex, and specifying zero or multiple capture groups causes an error.
How do I extract custom labels from log entries?
Use labelExtractors with a map of label keys to extractor expressions (same syntax as valueExtractor). Each label defined in metricDescriptor.labels must have a corresponding extractor in this map.
Naming & Constraints
What are the naming restrictions for metrics?
Metric names are limited to 100 characters and can only include: A-Z, a-z, 0-9, and the special characters _-.,+!*',()%/. Forward slashes denote hierarchy but cannot be the first character.
Can I move a metric to a different project or use a log bucket from another project?
No. The project property is immutable after creation, and bucketName must reference a log bucket in the same project as the metric.

Using a different cloud?

Explore monitoring guides for other cloud providers: