Skip to content
This repository was archived by the owner on Jun 2, 2021. It is now read-only.

Commit 9732ed2

Browse files
sethboyleschristarazi
authored andcommitted
Allow users to set custom metric tags
[Finishes #171285377] Co-authored-by: Seth Boyles <sboyles@pivotal.io> Co-authored-by: Chris Tarazi <ctarazi@pivotal.io>
1 parent 90b5158 commit 9732ed2

7 files changed

Lines changed: 142 additions & 14 deletions

File tree

config/cloud_controller.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,4 @@ locket:
400400
threadpool_size: 20
401401

402402
default_app_lifecycle: buildpack
403+
custom_metric_tag_prefix_list: ["metric.tag.cloudfoundry.org"]

lib/cloud_controller/config_schemas/api_schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ class ApiSchema < VCAP::Config
376376
}
377377
},
378378
default_app_lifecycle: String,
379+
custom_metric_tag_prefix_list: Array,
379380
}
380381
end
381382
# rubocop:enable Metrics/BlockLength

lib/cloud_controller/config_schemas/clock_schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class ClockSchema < VCAP::Config
209209

210210
max_labels_per_resource: Integer,
211211
max_annotations_per_resource: Integer,
212+
custom_metric_tag_prefix_list: Array,
212213
}
213214
end
214215
# rubocop:enable Metrics/BlockLength

lib/cloud_controller/config_schemas/deployment_updater_schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class DeploymentUpdaterSchema < VCAP::Config
170170

171171
max_labels_per_resource: Integer,
172172
max_annotations_per_resource: Integer,
173+
custom_metric_tag_prefix_list: Array,
173174
}
174175
end
175176
# rubocop:enable Metrics/BlockLength

lib/cloud_controller/config_schemas/worker_schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class WorkerSchema < VCAP::Config
209209
max_labels_per_resource: Integer,
210210
max_annotations_per_resource: Integer,
211211
internal_route_vip_range: String,
212+
custom_metric_tag_prefix_list: Array,
212213
}
213214
end
214215
# rubocop:enable Metrics/BlockLength

lib/cloud_controller/diego/app_recipe_builder.rb

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def app_lrp_arguments
6060
host_fingerprint: ssh_key.fingerprint
6161
})
6262
end
63+
6364
{
6465
process_guid: Diego::ProcessGuid.from_process(process),
6566
instances: process.desired_instances,
@@ -72,19 +73,7 @@ def app_lrp_arguments
7273
log_source: LRP_LOG_SOURCE,
7374
log_guid: process.app.guid,
7475
metrics_guid: process.app.guid,
75-
metric_tags: {
76-
'source_id' => METRIC_TAG_VALUE.new(static: process.app.guid),
77-
'process_id' => METRIC_TAG_VALUE.new(static: process.guid),
78-
'process_type' => METRIC_TAG_VALUE.new(static: process.type),
79-
'process_instance_id' => METRIC_TAG_VALUE.new(dynamic: METRIC_TAG_VALUE::DynamicValue::INSTANCE_GUID),
80-
'instance_id' => METRIC_TAG_VALUE.new(dynamic: METRIC_TAG_VALUE::DynamicValue::INDEX),
81-
'organization_id' => METRIC_TAG_VALUE.new(static: process.organization.guid),
82-
'space_id' => METRIC_TAG_VALUE.new(static: process.space.guid),
83-
'app_id' => METRIC_TAG_VALUE.new(static: process.app.guid),
84-
'organization_name' => METRIC_TAG_VALUE.new(static: process.organization.name),
85-
'space_name' => METRIC_TAG_VALUE.new(static: process.space.name),
86-
'app_name' => METRIC_TAG_VALUE.new(static: process.app.name),
87-
},
76+
metric_tags: metric_tags(process),
8877
annotation: process.updated_at.to_f.to_s,
8978
egress_rules: Diego::EgressRules.new.running_protobuf_rules(process),
9079
cached_dependencies: desired_lrp_builder.cached_dependencies,
@@ -111,6 +100,43 @@ def app_lrp_arguments
111100
}.compact
112101
end
113102

103+
def metric_tags(process)
104+
tags = {
105+
'source_id' => METRIC_TAG_VALUE.new(static: process.app.guid),
106+
'process_id' => METRIC_TAG_VALUE.new(static: process.guid),
107+
'process_type' => METRIC_TAG_VALUE.new(static: process.type),
108+
'process_instance_id' => METRIC_TAG_VALUE.new(dynamic: METRIC_TAG_VALUE::DynamicValue::INSTANCE_GUID),
109+
'instance_id' => METRIC_TAG_VALUE.new(dynamic: METRIC_TAG_VALUE::DynamicValue::INDEX),
110+
'organization_id' => METRIC_TAG_VALUE.new(static: process.organization.guid),
111+
'space_id' => METRIC_TAG_VALUE.new(static: process.space.guid),
112+
'app_id' => METRIC_TAG_VALUE.new(static: process.app.guid),
113+
'organization_name' => METRIC_TAG_VALUE.new(static: process.organization.name),
114+
'space_name' => METRIC_TAG_VALUE.new(static: process.space.name),
115+
'app_name' => METRIC_TAG_VALUE.new(static: process.app.name),
116+
}
117+
118+
metric_tag_label_prefixes = Config.config.get(:custom_metric_tag_prefix_list)
119+
unless metric_tag_label_prefixes.empty?
120+
# These should not be overridden by app developers. This list is based on
121+
# https://github.com/cloudfoundry/loggregator-agent-release/blob/8b714dc6f09cfa8a67d78ec974b77c0d7642f5a3/src/pkg/egress/v1/tagger.go#L32-L44
122+
# and is not expected to change
123+
reserved_key_names = %w(deployment index ip job)
124+
125+
process.app.labels.
126+
select { |label|
127+
metric_tag_label_prefixes.include?(label.key_prefix) && !tags.key?(label.key_name)
128+
}.
129+
reject { |label|
130+
reserved_key_names.include?(label.key_name)
131+
}.
132+
each { |label|
133+
tags[label.key_name] = METRIC_TAG_VALUE.new(static: label.value)
134+
}
135+
end
136+
137+
tags
138+
end
139+
114140
def routing_info
115141
@routing_info ||= Protocol::RoutingInfo.new(process).routing_info
116142
end

spec/unit/lib/cloud_controller/diego/app_recipe_builder_spec.rb

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module Diego
3232
end
3333

3434
let(:lifecycle_type) { nil }
35-
let(:org) { Organization.make }
35+
let(:org) { Organization.make(name: 'MyOrg') }
3636
let(:space) { Space.make(organization: org) }
3737
let(:app_model) { AppModel.make(lifecycle_type, guid: 'app-guid', space: space, droplet: DropletModel.make(state: 'STAGED'), enable_ssh: false) }
3838
let(:package) { PackageModel.make(lifecycle_type, app: app_model) }
@@ -893,6 +893,103 @@ module Diego
893893
expect(lrp.image_password).to eq('dockerpass')
894894
end
895895

896+
describe 'metric_tags' do
897+
let(:lrp) { builder.build_app_lrp }
898+
let(:metric_tag_key_prefix) { 'metric.tag.cloudfoundry.org' }
899+
900+
before do
901+
AppLabelModel.create(
902+
app: app_model,
903+
key_prefix: metric_tag_key_prefix,
904+
key_name: 'DatadogValue',
905+
value: 'woof'
906+
)
907+
908+
AppLabelModel.create(
909+
app: app_model,
910+
key_prefix: 'nonmetric.tag.cloudfoundry.org',
911+
key_name: 'SomeotherValue',
912+
value: 'notapplied'
913+
)
914+
end
915+
916+
context 'when cc.custom_metric_tag_prefix_list has entries' do
917+
before do
918+
TestConfig.override(custom_metric_tag_prefix_list: [metric_tag_key_prefix])
919+
end
920+
921+
it 'app labels set custom tags' do
922+
expect(lrp.metric_tags['DatadogValue'].static).to eq 'woof'
923+
expect(lrp.metric_tags['SomeotherValue']).to eq nil
924+
end
925+
926+
context 'when app labels tags match existing custom metrics tags' do
927+
before do
928+
AppLabelModel.create(
929+
app: app_model,
930+
key_prefix: metric_tag_key_prefix,
931+
key_name: 'organization_name',
932+
value: 'wrong_org_name'
933+
)
934+
end
935+
936+
it 'does not override the metric tag' do
937+
expect(lrp.metric_tags['organization_name'].static).to eq 'MyOrg'
938+
end
939+
end
940+
941+
context 'when app labels contain forbidden key_names' do
942+
before do
943+
AppLabelModel.create(
944+
app: app_model,
945+
key_prefix: metric_tag_key_prefix,
946+
key_name: 'deployment',
947+
value: 'kafka'
948+
)
949+
950+
AppLabelModel.create(
951+
app: app_model,
952+
key_prefix: metric_tag_key_prefix,
953+
key_name: 'index',
954+
value: '999'
955+
)
956+
957+
AppLabelModel.create(
958+
app: app_model,
959+
key_prefix: metric_tag_key_prefix,
960+
key_name: 'ip',
961+
value: '127.0.0.1'
962+
)
963+
964+
AppLabelModel.create(
965+
app: app_model,
966+
key_prefix: metric_tag_key_prefix,
967+
key_name: 'job',
968+
value: 'potato farmer'
969+
)
970+
end
971+
972+
it 'do not get applied' do
973+
expect(lrp.metric_tags['deployment']).to be_nil
974+
expect(lrp.metric_tags['index']).to be_nil
975+
expect(lrp.metric_tags['ip']).to be_nil
976+
expect(lrp.metric_tags['job']).to be_nil
977+
end
978+
end
979+
end
980+
981+
context 'when cc.custom_metric_tag_prefix_list is an empty list' do
982+
before do
983+
TestConfig.override(custom_metric_tag_prefix_list: [])
984+
end
985+
986+
it 'app labels do not set custom tags' do
987+
expect(lrp.metric_tags['DatadogValue']).to eq nil
988+
expect(lrp.metric_tags['SomeotherValue']).to eq nil
989+
end
990+
end
991+
end
992+
896993
context 'cpu weight' do
897994
context 'when the memory limit is between the minimum and maximum' do
898995
before { process.memory = (MIN_CPU_PROXY + MAX_CPU_PROXY) / 2 }

0 commit comments

Comments
 (0)