diff --git a/docs/resources/google_logging_project_sinks.md b/docs/resources/google_logging_project_sinks.md
index 44c254d2e..865a9163d 100644
--- a/docs/resources/google_logging_project_sinks.md
+++ b/docs/resources/google_logging_project_sinks.md
@@ -51,7 +51,7 @@ The following examples show how to use this InSpec audit resource.
### Test that a subset of all sinks matching "project*" have a particular writer identity
- google_logging_project_sinks(project: 'chef-inspec-gcp').sink_names.each do |sink_name|
+ google_logging_project_sinks(project: 'chef-inspec-gcp').where(sink_name: /project/).sink_names.each do |sink_name|
describe google_logging_project_sink(project: 'chef-inspec-gcp', sink: sink_name) do
its('writer_identity') { should eq "serviceAccount:my-logging-service-account.iam.gserviceaccount.com" }
end
diff --git a/docs/resources/google_project_metric.md b/docs/resources/google_project_metric.md
new file mode 100644
index 000000000..bc070c96a
--- /dev/null
+++ b/docs/resources/google_project_metric.md
@@ -0,0 +1,49 @@
+---
+title: About the google_project_metric Resource
+platform: gcp
+---
+
+# google\_project\_metric
+
+Use the `google_project_metric` InSpec audit resource to test properties of a single GCP project metric.
+
+
+
+## Syntax
+
+A `google_project_metric` resource block declares the tests for a single GCP zone by project and name.
+
+ describe google_project_metric(project: 'chef-inspec-gcp', metric: 'metric_name') do
+ it { should exist }
+ end
+
+
+
+## Examples
+
+The following examples show how to use this InSpec audit resource.
+
+### Test that a GCP project metric exists
+
+ describe google_project_metric(project: 'chef-inspec-gcp', metric: 'metric_name') do
+ it { should exist }
+ end
+
+### Test that a GCP compute zone has an expected CPU platform
+
+ describe google_project_metric(project: 'chef-inspec-gcp', metric: 'metric_name') do
+ its('filter') { should eq "(protoPayload.serviceName=\"cloudresourcemanager.googleapis.com\")" }
+ end
+
+
+
+## Properties
+
+* `filter`, `name`, `metric_descriptor`
+
+
+
+
+## GCP Permissions
+
+Ensure the [Stackdriver Logging API](https://console.cloud.google.com/apis/api/logging.googleapis.com/) is enabled for the project.
\ No newline at end of file
diff --git a/docs/resources/google_project_metrics.md b/docs/resources/google_project_metrics.md
new file mode 100644
index 000000000..b948f8ea1
--- /dev/null
+++ b/docs/resources/google_project_metrics.md
@@ -0,0 +1,70 @@
+---
+title: About the google_project_metrics Resource
+platform: gcp
+---
+
+# google\_project\_metrics
+
+Use the `google_project_metrics` InSpec audit resource to test properties of all, or a filtered group of, GCP project metrics.
+
+
+
+## Syntax
+
+A `google_project_metrics` resource block collects GCP project logging sinks by project then tests that group.
+
+ describe google_project_metrics(project: 'chef-inspec-gcp') do
+ it { should exist }
+ end
+
+Use this InSpec resource to enumerate IDs then test in-depth using `google_project_metric`.
+
+ google_project_metrics(project: 'chef-inspec-gcp').sink_names.each do |metric_name|
+ describe google_project_metric(project: 'chef-inspec-gcp', metric: metric_name) do
+ it { should exist }
+ end
+ end
+
+
+
+## Examples
+
+The following examples show how to use this InSpec audit resource.
+
+### Test that there are no more than a specified number of metrics available for the project
+
+ describe google_project_metrics(project: 'chef-inspec-gcp') do
+ its('count') { should be <= 100}
+ end
+
+### Test that an expected metric name is available for the project
+
+ describe google_project_metrics(project: 'chef-inspec-gcp') do
+ its('metric_names') { should include "metric-name" }
+ end
+
+### Test that a subset of all metrics with name matching "*project*" have a particular writer identity
+
+ google_project_metrics(project: 'chef-inspec-gcp').where(metric_name: /project/).metric_names.each do |metric_name|
+ describe google_project_metric(project: 'chef-inspec-gcp', metric: metric_name) do
+ its('filter') { should eq "(protoPayload.serviceName=\"cloudresourcemanager.googleapis.com\")" }
+ end
+ end
+
+
+
+## Filter Criteria
+
+This resource supports the following filter criteria: `metric_name` and `metric_filter`. Either of these may be used with `where`, as a block or as a method.
+
+## Properties
+
+* `metric_names` - an array of google_project_metric name strings
+* `metric_filters`- an array of google_project_metric filters
+
+
+
+
+## GCP Permissions
+
+Ensure the [Stackdriver Logging API](https://console.cloud.google.com/apis/api/logging.googleapis.com/) is enabled for the project.
\ No newline at end of file
diff --git a/libraries/google_project_metric.rb b/libraries/google_project_metric.rb
new file mode 100644
index 000000000..22d70a197
--- /dev/null
+++ b/libraries/google_project_metric.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'gcp_backend'
+
+module Inspec::Resources
+ class GoogleProjectMetric < GcpResourceBase
+ name 'google_project_metric'
+ desc 'Verifies settings for a project metric'
+
+ example "
+ describe google_project_metric(project: 'chef-inspec-gcp', metric: 'metric_name') do
+ it { should exist }
+ end
+ "
+
+ def initialize(opts = {})
+ # Call the parent class constructor
+ super(opts)
+ @display_name = opts[:metric]
+ catch_gcp_errors do
+ @metric = @gcp.gcp_client(Google::Apis::LoggingV2::LoggingService).get_project_metric("projects/#{opts[:project]}/metrics/#{opts[:metric]}")
+ create_resource_methods(@metric)
+ end
+ end
+
+ def exists?
+ !@metric.nil?
+ end
+
+ def to_s
+ "Project Metric #{@display_name}"
+ end
+ end
+end
diff --git a/libraries/google_project_metrics.rb b/libraries/google_project_metrics.rb
new file mode 100644
index 000000000..0ce2c5220
--- /dev/null
+++ b/libraries/google_project_metrics.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'gcp_backend'
+
+module Inspec::Resources
+ class GoogleProjectMetrics < GcpResourceBase
+ name 'google_project_metrics'
+ desc 'Verifies settings for GCP project metrics in bulk'
+
+ example "
+ describe google_project_metrics(project: 'chef-inspec-gcp') do
+ it { should exist }
+ end
+ "
+
+ def initialize(opts = {})
+ # Call the parent class constructor
+ super(opts)
+ @project = opts[:project]
+ end
+
+ # FilterTable setup
+ filter_table_config = FilterTable.create
+ filter_table_config.add(:metric_names, field: :metric_name)
+ filter_table_config.add(:metric_destinations, field: :metric_destination)
+ filter_table_config.connect(self, :fetch_data)
+
+ def fetch_data
+ metric_rows = []
+ next_page = nil
+ loop do
+ catch_gcp_errors do
+ @metrics = @gcp.gcp_client(Google::Apis::LoggingV2::LoggingService).list_project_metrics("projects/#{@project}", page_token: next_page)
+ end
+ return [] if !@metrics || !@metrics.metrics
+ @metrics.metrics.map do |metric|
+ metric_rows+=[{ metric_name: metric.name,
+ metric_filter: metric.filter }]
+ end
+ next_page = @metrics.next_page_token
+ break unless next_page
+ end
+ @table = metric_rows
+ end
+ end
+end
diff --git a/test/integration/verify/controls/google_logging_project_sinks.rb b/test/integration/verify/controls/google_logging_project_sinks.rb
index 9a2559ee4..6ad81f403 100644
--- a/test/integration/verify/controls/google_logging_project_sinks.rb
+++ b/test/integration/verify/controls/google_logging_project_sinks.rb
@@ -14,6 +14,6 @@
describe google_logging_project_sinks(project: gcp_project_id) do
it { should exist }
its('sink_names') { should include gcp_logging_project_sink_name }
- its('sink_destinations') { should eq "storage.googleapis.com/#{gcp_logging_bucket_name}" }
+ its('sink_destinations') { should include "storage.googleapis.com/#{gcp_logging_bucket_name}" }
end
end
\ No newline at end of file