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 Cloud Logging entries and expose them as Cloud Monitoring time series. This guide focuses on three capabilities: counter metrics with label extraction, distribution metrics with histogram buckets, and bucket scoping and metric lifecycle.

Logs-based metrics evaluate log entries using advanced filters and optionally reference specific log buckets. The examples are intentionally small. Combine them with your own alerting policies and dashboards.

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 the metric’s type: metricKind set to DELTA means the metric tracks changes over time, while valueType INT64 indicates it counts occurrences. This configuration creates a simple counter that increments each time a matching log entry appears.

Add dimensions to counters with label extraction

When counting events, you often need to group by dimensions like request type or user ID. Label extractors pull values from log fields and attach them as metric labels.

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 declares the dimensions you want to track. Each label needs a key, valueType, and optional description. The labelExtractors map connects each label key to an EXTRACT expression that pulls the value from a log field. Here, the “mass” label extracts from jsonPayload.request, allowing you to group error counts by that field’s value.

Create distribution metrics with histogram buckets

Some metrics need to track value distributions rather than simple counts, such as request latencies or payload sizes.

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 valueType set to DISTRIBUTION in the metricDescriptor. The valueExtractor property specifies which log field to extract numeric values from. The bucketOptions property defines histogram boundaries: linearBuckets creates evenly-spaced buckets starting at offset, with each bucket spanning width units. This configuration tracks both statistics (mean, standard deviation) and a histogram of the extracted values.

Scope metrics to a specific log bucket

By default, metrics evaluate logs across all buckets in a project. When you need to limit evaluation to a specific bucket, such as a dedicated security log bucket, use the bucketName property.

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 by name. The metric only evaluates log entries stored in that bucket, ignoring logs in other buckets. Both the bucket and metric must exist in the same project.

Disable metric collection without deletion

During troubleshooting or cost optimization, you may need to temporarily stop metric collection without losing the metric definition.

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 generating data points. The metric definition remains in Cloud Logging, and you can re-enable it by setting disabled to false. This is useful for temporarily reducing costs or pausing metrics during maintenance windows.

Beyond these examples

These snippets focus on specific metric-level features: counter and distribution metric types, label extraction and histogram bucketing, and bucket scoping and metric disabling. 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 metric configuration rather than provisioning the logging infrastructure.

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

  • Exponential and explicit bucket configurations
  • REGEXP_EXTRACT for complex field parsing
  • Metric alerting policies and notification channels
  • Metric retention and quota management

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 counter and distribution metrics?
Counter metrics use valueType: INT64 and count log entries matching the filter. Distribution metrics use valueType: DISTRIBUTION and require valueExtractor and bucketOptions to create histograms of extracted values.
What happens if I don't specify metricDescriptor?
The metric defaults to a DELTA metric kind with INT64 value type, no labels, and unit “1”, which counts the number of log entries matching the filter expression.
When do I need to specify valueExtractor?
valueExtractor is required when using a distribution metric (DISTRIBUTION value type) to extract values from log entries for the histogram.
When do I need to specify bucketOptions?
bucketOptions is required when the metric uses a DISTRIBUTION value type to define the bucket boundaries for the histogram.
Value Extraction & Labels
What extraction functions can I use in valueExtractor?
Two functions are supported: EXTRACT(field) to extract a log entry field, or REGEXP_EXTRACT(field, regex) to extract using a regular expression with Google RE2 syntax.
What happens if my regex doesn't have exactly one capture group?
Using REGEXP_EXTRACT with a regex that doesn’t include exactly one capture group will cause an error. The regex must have precisely one capture group to extract data.
How do I add custom labels to my metric?
Define labels in metricDescriptor.labels with key, valueType, and description, then provide corresponding extractor expressions in labelExtractors using the same syntax as valueExtractor.
Naming & Project Constraints
What are the naming restrictions for metric identifiers?
Metric names are limited to 100 characters and can only include A-Z, a-z, 0-9, and special characters _-.,+!*',()%/. The forward slash (/) denotes hierarchy and cannot be the first character.
Can I change the project after creating a metric?
No, the project property is immutable and cannot be changed after the metric is created.
Log Buckets & Management
Can I associate a metric with a specific log bucket?
Yes, set bucketName to the resource name of the Log Bucket. The bucket must be in the same project as the metric.
How do I temporarily disable a metric without deleting it?
Set disabled: true to stop the metric from generating points while keeping the configuration intact.

Using a different cloud?

Explore monitoring guides for other cloud providers: