Configure GCP Service-Level Objectives

The gcp:monitoring/slo:Slo resource, part of the Pulumi GCP provider, defines Service-Level Objectives that measure service quality against performance goals over evaluation periods. This guide focuses on three capabilities: basic SLIs for App Engine latency, request-based SLIs with distribution cuts, and windows-based SLIs for time-series evaluation.

SLOs belong to monitoring services and reference metric data from Cloud Monitoring. The examples are intentionally small. Combine them with your own services, alert policies, and notification channels.

Track App Engine latency with basic SLI

Teams monitoring App Engine services often start with latency-based SLOs that measure whether requests complete within acceptable time bounds.

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

const _default = gcp.monitoring.getAppEngineService({
    moduleId: "default",
});
const appengSlo = new gcp.monitoring.Slo("appeng_slo", {
    service: _default.then(_default => _default.serviceId),
    sloId: "ae-slo",
    displayName: "Test SLO for App Engine",
    goal: 0.9,
    calendarPeriod: "DAY",
    basicSli: {
        latency: {
            threshold: "1s",
        },
    },
    userLabels: {
        my_key: "my_value",
        my_other_key: "my_other_value",
    },
});
import pulumi
import pulumi_gcp as gcp

default = gcp.monitoring.get_app_engine_service(module_id="default")
appeng_slo = gcp.monitoring.Slo("appeng_slo",
    service=default.service_id,
    slo_id="ae-slo",
    display_name="Test SLO for App Engine",
    goal=0.9,
    calendar_period="DAY",
    basic_sli={
        "latency": {
            "threshold": "1s",
        },
    },
    user_labels={
        "my_key": "my_value",
        "my_other_key": "my_other_value",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := monitoring.GetAppEngineService(ctx, &monitoring.GetAppEngineServiceArgs{
			ModuleId: "default",
		}, nil)
		if err != nil {
			return err
		}
		_, err = monitoring.NewSlo(ctx, "appeng_slo", &monitoring.SloArgs{
			Service:        pulumi.String(_default.ServiceId),
			SloId:          pulumi.String("ae-slo"),
			DisplayName:    pulumi.String("Test SLO for App Engine"),
			Goal:           pulumi.Float64(0.9),
			CalendarPeriod: pulumi.String("DAY"),
			BasicSli: &monitoring.SloBasicSliArgs{
				Latency: &monitoring.SloBasicSliLatencyArgs{
					Threshold: pulumi.String("1s"),
				},
			},
			UserLabels: pulumi.StringMap{
				"my_key":       pulumi.String("my_value"),
				"my_other_key": pulumi.String("my_other_value"),
			},
		})
		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 @default = Gcp.Monitoring.GetAppEngineService.Invoke(new()
    {
        ModuleId = "default",
    });

    var appengSlo = new Gcp.Monitoring.Slo("appeng_slo", new()
    {
        Service = @default.Apply(@default => @default.Apply(getAppEngineServiceResult => getAppEngineServiceResult.ServiceId)),
        SloId = "ae-slo",
        DisplayName = "Test SLO for App Engine",
        Goal = 0.9,
        CalendarPeriod = "DAY",
        BasicSli = new Gcp.Monitoring.Inputs.SloBasicSliArgs
        {
            Latency = new Gcp.Monitoring.Inputs.SloBasicSliLatencyArgs
            {
                Threshold = "1s",
            },
        },
        UserLabels = 
        {
            { "my_key", "my_value" },
            { "my_other_key", "my_other_value" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.monitoring.MonitoringFunctions;
import com.pulumi.gcp.monitoring.inputs.GetAppEngineServiceArgs;
import com.pulumi.gcp.monitoring.Slo;
import com.pulumi.gcp.monitoring.SloArgs;
import com.pulumi.gcp.monitoring.inputs.SloBasicSliArgs;
import com.pulumi.gcp.monitoring.inputs.SloBasicSliLatencyArgs;
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) {
        final var default = MonitoringFunctions.getAppEngineService(GetAppEngineServiceArgs.builder()
            .moduleId("default")
            .build());

        var appengSlo = new Slo("appengSlo", SloArgs.builder()
            .service(default_.serviceId())
            .sloId("ae-slo")
            .displayName("Test SLO for App Engine")
            .goal(0.9)
            .calendarPeriod("DAY")
            .basicSli(SloBasicSliArgs.builder()
                .latency(SloBasicSliLatencyArgs.builder()
                    .threshold("1s")
                    .build())
                .build())
            .userLabels(Map.ofEntries(
                Map.entry("my_key", "my_value"),
                Map.entry("my_other_key", "my_other_value")
            ))
            .build());

    }
}
resources:
  appengSlo:
    type: gcp:monitoring:Slo
    name: appeng_slo
    properties:
      service: ${default.serviceId}
      sloId: ae-slo
      displayName: Test SLO for App Engine
      goal: 0.9
      calendarPeriod: DAY
      basicSli:
        latency:
          threshold: 1s
      userLabels:
        my_key: my_value
        my_other_key: my_other_value
variables:
  default:
    fn::invoke:
      function: gcp:monitoring:getAppEngineService
      arguments:
        moduleId: default

The basicSli property uses pre-defined metrics for well-known service types like App Engine. The latency threshold sets the maximum acceptable request duration (1 second here). The goal property defines the target fraction of good service (0.9 means 90%), and calendarPeriod evaluates compliance daily.

Measure API latency with distribution cuts

Request-based SLIs count individual requests and classify them as good or bad based on distribution metrics.

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

const customsrv = new gcp.monitoring.CustomService("customsrv", {
    serviceId: "custom-srv-request-slos",
    displayName: "My Custom Service",
});
const requestBasedSlo = new gcp.monitoring.Slo("request_based_slo", {
    service: customsrv.serviceId,
    sloId: "consumed-api-slo",
    displayName: "Test SLO with request based SLI (good total ratio)",
    goal: 0.9,
    rollingPeriodDays: 30,
    requestBasedSli: {
        distributionCut: {
            distributionFilter: "metric.type=\"serviceruntime.googleapis.com/api/request_latencies\" resource.type=\"api\"  ",
            range: {
                max: 0.5,
            },
        },
    },
});
import pulumi
import pulumi_gcp as gcp

customsrv = gcp.monitoring.CustomService("customsrv",
    service_id="custom-srv-request-slos",
    display_name="My Custom Service")
request_based_slo = gcp.monitoring.Slo("request_based_slo",
    service=customsrv.service_id,
    slo_id="consumed-api-slo",
    display_name="Test SLO with request based SLI (good total ratio)",
    goal=0.9,
    rolling_period_days=30,
    request_based_sli={
        "distribution_cut": {
            "distribution_filter": "metric.type=\"serviceruntime.googleapis.com/api/request_latencies\" resource.type=\"api\"  ",
            "range": {
                "max": 0.5,
            },
        },
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		customsrv, err := monitoring.NewCustomService(ctx, "customsrv", &monitoring.CustomServiceArgs{
			ServiceId:   pulumi.String("custom-srv-request-slos"),
			DisplayName: pulumi.String("My Custom Service"),
		})
		if err != nil {
			return err
		}
		_, err = monitoring.NewSlo(ctx, "request_based_slo", &monitoring.SloArgs{
			Service:           customsrv.ServiceId,
			SloId:             pulumi.String("consumed-api-slo"),
			DisplayName:       pulumi.String("Test SLO with request based SLI (good total ratio)"),
			Goal:              pulumi.Float64(0.9),
			RollingPeriodDays: pulumi.Int(30),
			RequestBasedSli: &monitoring.SloRequestBasedSliArgs{
				DistributionCut: &monitoring.SloRequestBasedSliDistributionCutArgs{
					DistributionFilter: pulumi.String("metric.type=\"serviceruntime.googleapis.com/api/request_latencies\" resource.type=\"api\"  "),
					Range: &monitoring.SloRequestBasedSliDistributionCutRangeArgs{
						Max: pulumi.Float64(0.5),
					},
				},
			},
		})
		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 customsrv = new Gcp.Monitoring.CustomService("customsrv", new()
    {
        ServiceId = "custom-srv-request-slos",
        DisplayName = "My Custom Service",
    });

    var requestBasedSlo = new Gcp.Monitoring.Slo("request_based_slo", new()
    {
        Service = customsrv.ServiceId,
        SloId = "consumed-api-slo",
        DisplayName = "Test SLO with request based SLI (good total ratio)",
        Goal = 0.9,
        RollingPeriodDays = 30,
        RequestBasedSli = new Gcp.Monitoring.Inputs.SloRequestBasedSliArgs
        {
            DistributionCut = new Gcp.Monitoring.Inputs.SloRequestBasedSliDistributionCutArgs
            {
                DistributionFilter = "metric.type=\"serviceruntime.googleapis.com/api/request_latencies\" resource.type=\"api\"  ",
                Range = new Gcp.Monitoring.Inputs.SloRequestBasedSliDistributionCutRangeArgs
                {
                    Max = 0.5,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.monitoring.CustomService;
import com.pulumi.gcp.monitoring.CustomServiceArgs;
import com.pulumi.gcp.monitoring.Slo;
import com.pulumi.gcp.monitoring.SloArgs;
import com.pulumi.gcp.monitoring.inputs.SloRequestBasedSliArgs;
import com.pulumi.gcp.monitoring.inputs.SloRequestBasedSliDistributionCutArgs;
import com.pulumi.gcp.monitoring.inputs.SloRequestBasedSliDistributionCutRangeArgs;
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 customsrv = new CustomService("customsrv", CustomServiceArgs.builder()
            .serviceId("custom-srv-request-slos")
            .displayName("My Custom Service")
            .build());

        var requestBasedSlo = new Slo("requestBasedSlo", SloArgs.builder()
            .service(customsrv.serviceId())
            .sloId("consumed-api-slo")
            .displayName("Test SLO with request based SLI (good total ratio)")
            .goal(0.9)
            .rollingPeriodDays(30)
            .requestBasedSli(SloRequestBasedSliArgs.builder()
                .distributionCut(SloRequestBasedSliDistributionCutArgs.builder()
                    .distributionFilter("metric.type=\"serviceruntime.googleapis.com/api/request_latencies\" resource.type=\"api\"  ")
                    .range(SloRequestBasedSliDistributionCutRangeArgs.builder()
                        .max(0.5)
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  customsrv:
    type: gcp:monitoring:CustomService
    properties:
      serviceId: custom-srv-request-slos
      displayName: My Custom Service
  requestBasedSlo:
    type: gcp:monitoring:Slo
    name: request_based_slo
    properties:
      service: ${customsrv.serviceId}
      sloId: consumed-api-slo
      displayName: Test SLO with request based SLI (good total ratio)
      goal: 0.9
      rollingPeriodDays: 30
      requestBasedSli:
        distributionCut:
          distributionFilter: 'metric.type="serviceruntime.googleapis.com/api/request_latencies" resource.type="api"  '
          range:
            max: 0.5

The requestBasedSli property defines criteria for counting good requests. The distributionCut evaluates a metric distribution (API request latencies) and classifies requests below the range.max threshold as good. The rollingPeriodDays property evaluates the SLO over the past 30 days rather than calendar boundaries.

Evaluate uptime checks with time windows

Windows-based SLIs divide time into fixed windows and evaluate whether each window meets quality criteria.

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

const customsrv = new gcp.monitoring.CustomService("customsrv", {
    serviceId: "custom-srv-windows-slos",
    displayName: "My Custom Service",
});
const windowsBased = new gcp.monitoring.Slo("windows_based", {
    service: customsrv.serviceId,
    displayName: "Test SLO with window based SLI",
    goal: 0.95,
    calendarPeriod: "FORTNIGHT",
    windowsBasedSli: {
        windowPeriod: "400s",
        goodBadMetricFilter: std.join({
            separator: " AND ",
            input: [
                "metric.type=\"monitoring.googleapis.com/uptime_check/check_passed\"",
                "resource.type=\"uptime_url\"",
            ],
        }).then(invoke => invoke.result),
    },
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std

customsrv = gcp.monitoring.CustomService("customsrv",
    service_id="custom-srv-windows-slos",
    display_name="My Custom Service")
windows_based = gcp.monitoring.Slo("windows_based",
    service=customsrv.service_id,
    display_name="Test SLO with window based SLI",
    goal=0.95,
    calendar_period="FORTNIGHT",
    windows_based_sli={
        "window_period": "400s",
        "good_bad_metric_filter": std.join(separator=" AND ",
            input=[
                "metric.type=\"monitoring.googleapis.com/uptime_check/check_passed\"",
                "resource.type=\"uptime_url\"",
            ]).result,
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		customsrv, err := monitoring.NewCustomService(ctx, "customsrv", &monitoring.CustomServiceArgs{
			ServiceId:   pulumi.String("custom-srv-windows-slos"),
			DisplayName: pulumi.String("My Custom Service"),
		})
		if err != nil {
			return err
		}
		invokeJoin, err := std.Join(ctx, &std.JoinArgs{
			Separator: " AND ",
			Input: []string{
				"metric.type=\"monitoring.googleapis.com/uptime_check/check_passed\"",
				"resource.type=\"uptime_url\"",
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = monitoring.NewSlo(ctx, "windows_based", &monitoring.SloArgs{
			Service:        customsrv.ServiceId,
			DisplayName:    pulumi.String("Test SLO with window based SLI"),
			Goal:           pulumi.Float64(0.95),
			CalendarPeriod: pulumi.String("FORTNIGHT"),
			WindowsBasedSli: &monitoring.SloWindowsBasedSliArgs{
				WindowPeriod:        pulumi.String("400s"),
				GoodBadMetricFilter: pulumi.String(invokeJoin.Result),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var customsrv = new Gcp.Monitoring.CustomService("customsrv", new()
    {
        ServiceId = "custom-srv-windows-slos",
        DisplayName = "My Custom Service",
    });

    var windowsBased = new Gcp.Monitoring.Slo("windows_based", new()
    {
        Service = customsrv.ServiceId,
        DisplayName = "Test SLO with window based SLI",
        Goal = 0.95,
        CalendarPeriod = "FORTNIGHT",
        WindowsBasedSli = new Gcp.Monitoring.Inputs.SloWindowsBasedSliArgs
        {
            WindowPeriod = "400s",
            GoodBadMetricFilter = Std.Join.Invoke(new()
            {
                Separator = " AND ",
                Input = new[]
                {
                    "metric.type=\"monitoring.googleapis.com/uptime_check/check_passed\"",
                    "resource.type=\"uptime_url\"",
                },
            }).Apply(invoke => invoke.Result),
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.monitoring.CustomService;
import com.pulumi.gcp.monitoring.CustomServiceArgs;
import com.pulumi.gcp.monitoring.Slo;
import com.pulumi.gcp.monitoring.SloArgs;
import com.pulumi.gcp.monitoring.inputs.SloWindowsBasedSliArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.JoinArgs;
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 customsrv = new CustomService("customsrv", CustomServiceArgs.builder()
            .serviceId("custom-srv-windows-slos")
            .displayName("My Custom Service")
            .build());

        var windowsBased = new Slo("windowsBased", SloArgs.builder()
            .service(customsrv.serviceId())
            .displayName("Test SLO with window based SLI")
            .goal(0.95)
            .calendarPeriod("FORTNIGHT")
            .windowsBasedSli(SloWindowsBasedSliArgs.builder()
                .windowPeriod("400s")
                .goodBadMetricFilter(StdFunctions.join(JoinArgs.builder()
                    .separator(" AND ")
                    .input(                    
                        "metric.type=\"monitoring.googleapis.com/uptime_check/check_passed\"",
                        "resource.type=\"uptime_url\"")
                    .build()).result())
                .build())
            .build());

    }
}
resources:
  customsrv:
    type: gcp:monitoring:CustomService
    properties:
      serviceId: custom-srv-windows-slos
      displayName: My Custom Service
  windowsBased:
    type: gcp:monitoring:Slo
    name: windows_based
    properties:
      service: ${customsrv.serviceId}
      displayName: Test SLO with window based SLI
      goal: 0.95
      calendarPeriod: FORTNIGHT
      windowsBasedSli:
        windowPeriod: 400s
        goodBadMetricFilter:
          fn::invoke:
            function: std:join
            arguments:
              separator: ' AND '
              input:
                - metric.type="monitoring.googleapis.com/uptime_check/check_passed"
                - resource.type="uptime_url"
            return: result

The windowsBasedSli property splits the evaluation period into windows of windowPeriod duration (400 seconds). The goodBadMetricFilter identifies which time windows contain good service by filtering uptime check metrics. This approach suits monitoring systems where service quality varies over time rather than per-request.

Monitor mean latency within time windows

Some SLOs track whether average metric values stay within acceptable ranges during each time window.

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

const customsrv = new gcp.monitoring.CustomService("customsrv", {
    serviceId: "custom-srv-windows-slos",
    displayName: "My Custom Service",
});
const windowsBased = new gcp.monitoring.Slo("windows_based", {
    service: customsrv.serviceId,
    displayName: "Test SLO with window based SLI",
    goal: 0.9,
    rollingPeriodDays: 20,
    windowsBasedSli: {
        windowPeriod: "600s",
        metricMeanInRange: {
            timeSeries: std.join({
                separator: " AND ",
                input: [
                    "metric.type=\"agent.googleapis.com/cassandra/client_request/latency/95p\"",
                    "resource.type=\"gce_instance\"",
                ],
            }).then(invoke => invoke.result),
            range: {
                max: 5,
            },
        },
    },
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std

customsrv = gcp.monitoring.CustomService("customsrv",
    service_id="custom-srv-windows-slos",
    display_name="My Custom Service")
windows_based = gcp.monitoring.Slo("windows_based",
    service=customsrv.service_id,
    display_name="Test SLO with window based SLI",
    goal=0.9,
    rolling_period_days=20,
    windows_based_sli={
        "window_period": "600s",
        "metric_mean_in_range": {
            "time_series": std.join(separator=" AND ",
                input=[
                    "metric.type=\"agent.googleapis.com/cassandra/client_request/latency/95p\"",
                    "resource.type=\"gce_instance\"",
                ]).result,
            "range": {
                "max": 5,
            },
        },
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		customsrv, err := monitoring.NewCustomService(ctx, "customsrv", &monitoring.CustomServiceArgs{
			ServiceId:   pulumi.String("custom-srv-windows-slos"),
			DisplayName: pulumi.String("My Custom Service"),
		})
		if err != nil {
			return err
		}
		invokeJoin, err := std.Join(ctx, &std.JoinArgs{
			Separator: " AND ",
			Input: []string{
				"metric.type=\"agent.googleapis.com/cassandra/client_request/latency/95p\"",
				"resource.type=\"gce_instance\"",
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = monitoring.NewSlo(ctx, "windows_based", &monitoring.SloArgs{
			Service:           customsrv.ServiceId,
			DisplayName:       pulumi.String("Test SLO with window based SLI"),
			Goal:              pulumi.Float64(0.9),
			RollingPeriodDays: pulumi.Int(20),
			WindowsBasedSli: &monitoring.SloWindowsBasedSliArgs{
				WindowPeriod: pulumi.String("600s"),
				MetricMeanInRange: &monitoring.SloWindowsBasedSliMetricMeanInRangeArgs{
					TimeSeries: pulumi.String(invokeJoin.Result),
					Range: &monitoring.SloWindowsBasedSliMetricMeanInRangeRangeArgs{
						Max: pulumi.Float64(5),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var customsrv = new Gcp.Monitoring.CustomService("customsrv", new()
    {
        ServiceId = "custom-srv-windows-slos",
        DisplayName = "My Custom Service",
    });

    var windowsBased = new Gcp.Monitoring.Slo("windows_based", new()
    {
        Service = customsrv.ServiceId,
        DisplayName = "Test SLO with window based SLI",
        Goal = 0.9,
        RollingPeriodDays = 20,
        WindowsBasedSli = new Gcp.Monitoring.Inputs.SloWindowsBasedSliArgs
        {
            WindowPeriod = "600s",
            MetricMeanInRange = new Gcp.Monitoring.Inputs.SloWindowsBasedSliMetricMeanInRangeArgs
            {
                TimeSeries = Std.Join.Invoke(new()
                {
                    Separator = " AND ",
                    Input = new[]
                    {
                        "metric.type=\"agent.googleapis.com/cassandra/client_request/latency/95p\"",
                        "resource.type=\"gce_instance\"",
                    },
                }).Apply(invoke => invoke.Result),
                Range = new Gcp.Monitoring.Inputs.SloWindowsBasedSliMetricMeanInRangeRangeArgs
                {
                    Max = 5,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.monitoring.CustomService;
import com.pulumi.gcp.monitoring.CustomServiceArgs;
import com.pulumi.gcp.monitoring.Slo;
import com.pulumi.gcp.monitoring.SloArgs;
import com.pulumi.gcp.monitoring.inputs.SloWindowsBasedSliArgs;
import com.pulumi.gcp.monitoring.inputs.SloWindowsBasedSliMetricMeanInRangeArgs;
import com.pulumi.gcp.monitoring.inputs.SloWindowsBasedSliMetricMeanInRangeRangeArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.JoinArgs;
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 customsrv = new CustomService("customsrv", CustomServiceArgs.builder()
            .serviceId("custom-srv-windows-slos")
            .displayName("My Custom Service")
            .build());

        var windowsBased = new Slo("windowsBased", SloArgs.builder()
            .service(customsrv.serviceId())
            .displayName("Test SLO with window based SLI")
            .goal(0.9)
            .rollingPeriodDays(20)
            .windowsBasedSli(SloWindowsBasedSliArgs.builder()
                .windowPeriod("600s")
                .metricMeanInRange(SloWindowsBasedSliMetricMeanInRangeArgs.builder()
                    .timeSeries(StdFunctions.join(JoinArgs.builder()
                        .separator(" AND ")
                        .input(                        
                            "metric.type=\"agent.googleapis.com/cassandra/client_request/latency/95p\"",
                            "resource.type=\"gce_instance\"")
                        .build()).result())
                    .range(SloWindowsBasedSliMetricMeanInRangeRangeArgs.builder()
                        .max(5.0)
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  customsrv:
    type: gcp:monitoring:CustomService
    properties:
      serviceId: custom-srv-windows-slos
      displayName: My Custom Service
  windowsBased:
    type: gcp:monitoring:Slo
    name: windows_based
    properties:
      service: ${customsrv.serviceId}
      displayName: Test SLO with window based SLI
      goal: 0.9
      rollingPeriodDays: 20
      windowsBasedSli:
        windowPeriod: 600s
        metricMeanInRange:
          timeSeries:
            fn::invoke:
              function: std:join
              arguments:
                separator: ' AND '
                input:
                  - metric.type="agent.googleapis.com/cassandra/client_request/latency/95p"
                  - resource.type="gce_instance"
              return: result
          range:
            max: 5

The metricMeanInRange property calculates the mean of a time series within each window and checks whether it falls within the specified range. Here, Cassandra 95th percentile latency must stay below 5ms. The timeSeries filter identifies which metrics to aggregate.

Beyond these examples

These snippets focus on specific SLO features: basic SLIs for well-known services, request-based and windows-based SLI types, and distribution cuts and metric aggregations. They’re intentionally minimal rather than full monitoring solutions.

The examples reference pre-existing infrastructure such as monitoring services (App Engine, custom services) and metric data from Cloud Monitoring. They focus on configuring the SLO rather than provisioning the underlying services.

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

  • User labels for organization (userLabels)
  • Metric sum aggregations (metricSumInRange)
  • Ratio thresholds with performance criteria (goodTotalRatioThreshold)
  • Alert policy integration

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

Let's configure GCP Service-Level Objectives

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

SLI Configuration
Which SLI type should I use for my service level objective?
You must choose exactly one of three SLI types: basicSli for well-known service types with pre-defined metrics (like App Engine latency), requestBasedSli for counting atomic service units directly (like API request success rates), or windowsBasedSli for time-window-based criteria (like uptime checks or metric aggregations over windows).
Can I specify multiple SLI types for the same SLO?
No, you must specify exactly one SLI type. Configuring multiple SLI types or omitting all of them will cause an error.
Goal & Period Settings
What are the valid values for the goal parameter?
The goal must be greater than 0 and less than or equal to 0.999 (99.9%). For example, goal: 0.9 represents a 90% service level objective.
What's the difference between calendarPeriod and rollingPeriodDays?
calendarPeriod evaluates the SLO since the start of the current period (DAY, WEEK, FORTNIGHT, or MONTH), while rollingPeriodDays uses a sliding window of the past 1-30 days. Choose calendar periods for alignment with business cycles or rolling periods for continuous monitoring.
What calendar period options are available?
You can use DAY, WEEK, FORTNIGHT, or MONTH as calendar periods.
What's the valid range for rollingPeriodDays?
rollingPeriodDays must be between 1 and 30 days, inclusive.
Immutability & Updates
What properties can't I change after creating an SLO?
The project, service, and sloId properties are immutable and cannot be changed after creation. Modifying these values requires replacing the resource.
Labels & Metadata
What are the limits for userLabels?
You can add up to 64 label entries. Each key and value is limited to 63 Unicode characters or 128 bytes (whichever is smaller). Labels can contain only lowercase letters, numerals, underscores, and dashes, and keys must begin with a letter.

Using a different cloud?

Explore monitoring guides for other cloud providers: