|
9 | 9 | "sync/atomic" |
10 | 10 |
|
11 | 11 | "github.com/cockroachdb/cockroach/pkg/util/metric" |
12 | | - "github.com/cockroachdb/errors" |
| 12 | + "github.com/cockroachdb/cockroach/pkg/util/syncutil" |
13 | 13 | "github.com/gogo/protobuf/proto" |
14 | 14 | io_prometheus_client "github.com/prometheus/client_model/go" |
15 | 15 | ) |
@@ -83,29 +83,6 @@ func (c *AggCounter) AddChild(labelVals ...string) *Counter { |
83 | 83 | return child |
84 | 84 | } |
85 | 85 |
|
86 | | -// Inc increments the counter value by i for the given label values. If a |
87 | | -// counter with the given label values doesn't exist yet, it creates a new |
88 | | -// counter and increments it. Panics if the number of label values doesn't |
89 | | -// match the number of labels defined for this counter and if the storage type |
90 | | -// is not StorageTypeCache. |
91 | | -func (c *AggCounter) Inc(i int64, labelVals ...string) { |
92 | | - if len(c.labels) != len(labelVals) { |
93 | | - panic(errors.AssertionFailedf( |
94 | | - "cannot increment child with %d label values %v to a metric with %d labels %v", |
95 | | - len(labelVals), labelVals, len(c.labels), c.labels)) |
96 | | - } |
97 | | - |
98 | | - // If the child already exists, increment it. |
99 | | - if child, ok := c.get(labelVals...); ok { |
100 | | - child.(*Counter).Inc(i) |
101 | | - return |
102 | | - } |
103 | | - |
104 | | - // Otherwise, create a new child and increment it. |
105 | | - child := c.AddChild(labelVals...) |
106 | | - child.Inc(i) |
107 | | -} |
108 | | - |
109 | 86 | // RemoveChild removes a Gauge from this AggGauge. This method panics if a Gauge |
110 | 87 | // does not exist for this set of labelVals. |
111 | 88 | func (g *AggCounter) RemoveChild(labelVals ...string) { |
@@ -267,3 +244,188 @@ func (g *CounterFloat64) Inc(i float64) { |
267 | 244 | func (g *CounterFloat64) UpdateIfHigher(i float64) { |
268 | 245 | g.value.UpdateIfHigher(i) |
269 | 246 | } |
| 247 | + |
| 248 | +// SQLCounter maintains a value as the sum of its children. The counter will |
| 249 | +// report to crdb-internal time series only the aggregate sum of all of its |
| 250 | +// children, while its children are additionally exported to prometheus via the |
| 251 | +// PrometheusIterable interface. SQLCounter differs from AggCounter in that |
| 252 | +// a SQLCounter creates child metrics dynamically while AggCounter needs the |
| 253 | +// child creation up front. |
| 254 | +type SQLCounter struct { |
| 255 | + g metric.Counter |
| 256 | + labelConfig atomic.Uint64 |
| 257 | + mu struct { |
| 258 | + syncutil.Mutex |
| 259 | + children ChildrenStorage |
| 260 | + } |
| 261 | +} |
| 262 | + |
| 263 | +func (c *SQLCounter) Each( |
| 264 | + labels []*io_prometheus_client.LabelPair, f func(metric *io_prometheus_client.Metric), |
| 265 | +) { |
| 266 | + c.mu.Lock() |
| 267 | + defer c.mu.Unlock() |
| 268 | + |
| 269 | + c.mu.children.Do(func(e interface{}) { |
| 270 | + cm := c.mu.children.GetChildMetric(e) |
| 271 | + pm := cm.ToPrometheusMetric() |
| 272 | + |
| 273 | + childLabels := make([]*io_prometheus_client.LabelPair, 0, len(labels)+2) |
| 274 | + childLabels = append(childLabels, labels...) |
| 275 | + lvs := cm.labelValues() |
| 276 | + dbLabel := dbLabel |
| 277 | + appLabel := appLabel |
| 278 | + switch c.labelConfig.Load() { |
| 279 | + case LabelConfigDB: |
| 280 | + childLabels = append(childLabels, &io_prometheus_client.LabelPair{ |
| 281 | + Name: &dbLabel, |
| 282 | + Value: &lvs[0], |
| 283 | + }) |
| 284 | + case LabelConfigApp: |
| 285 | + childLabels = append(childLabels, &io_prometheus_client.LabelPair{ |
| 286 | + Name: &appLabel, |
| 287 | + Value: &lvs[0], |
| 288 | + }) |
| 289 | + case LabelConfigAppAndDB: |
| 290 | + childLabels = append(childLabels, &io_prometheus_client.LabelPair{ |
| 291 | + Name: &dbLabel, |
| 292 | + Value: &lvs[0], |
| 293 | + }) |
| 294 | + childLabels = append(childLabels, &io_prometheus_client.LabelPair{ |
| 295 | + Name: &appLabel, |
| 296 | + Value: &lvs[1], |
| 297 | + }) |
| 298 | + default: |
| 299 | + } |
| 300 | + pm.Label = childLabels |
| 301 | + f(pm) |
| 302 | + }) |
| 303 | +} |
| 304 | + |
| 305 | +var _ metric.Iterable = (*SQLCounter)(nil) |
| 306 | +var _ metric.PrometheusIterable = (*SQLCounter)(nil) |
| 307 | +var _ metric.PrometheusExportable = (*SQLCounter)(nil) |
| 308 | + |
| 309 | +// NewSQLCounter constructs a new SQLCounter. |
| 310 | +func NewSQLCounter(metadata metric.Metadata) *SQLCounter { |
| 311 | + c := &SQLCounter{ |
| 312 | + g: *metric.NewCounter(metadata), |
| 313 | + } |
| 314 | + c.mu.children = &UnorderedCacheWrapper{ |
| 315 | + cache: getCacheStorage(), |
| 316 | + } |
| 317 | + c.labelConfig.Store(LabelConfigDisabled) |
| 318 | + return c |
| 319 | +} |
| 320 | + |
| 321 | +// getOrAddChild returns the child metric for the given label values. If the child |
| 322 | +// doesn't exist, it creates a new one and adds it to the collection. |
| 323 | +func (c *SQLCounter) getOrAddChild(labelValues ...string) ChildMetric { |
| 324 | + c.mu.Lock() |
| 325 | + defer c.mu.Unlock() |
| 326 | + |
| 327 | + // If the child already exists, return it. |
| 328 | + if child, ok := c.mu.children.Get(labelValues...); ok { |
| 329 | + return child |
| 330 | + } |
| 331 | + |
| 332 | + // Otherwise, create a new child and return it. |
| 333 | + child := &SQLChildCounter{ |
| 334 | + labelValuesSlice: labelValuesSlice(labelValues), |
| 335 | + } |
| 336 | + c.mu.children.Add(child) |
| 337 | + return child |
| 338 | +} |
| 339 | + |
| 340 | +// GetType is part of the metric.PrometheusExportable interface. |
| 341 | +func (c *SQLCounter) GetType() *io_prometheus_client.MetricType { |
| 342 | + return c.g.GetType() |
| 343 | +} |
| 344 | + |
| 345 | +// GetLabels is part of the metric.PrometheusExportable interface. |
| 346 | +func (c *SQLCounter) GetLabels(useStaticLabels bool) []*io_prometheus_client.LabelPair { |
| 347 | + return c.g.GetLabels(useStaticLabels) |
| 348 | +} |
| 349 | + |
| 350 | +// ToPrometheusMetric is part of the metric.PrometheusExportable interface. |
| 351 | +func (c *SQLCounter) ToPrometheusMetric() *io_prometheus_client.Metric { |
| 352 | + return c.g.ToPrometheusMetric() |
| 353 | +} |
| 354 | + |
| 355 | +// GetName is part of the metric.Iterable interface. |
| 356 | +func (c *SQLCounter) GetName(useStaticLabels bool) string { |
| 357 | + return c.g.GetName(useStaticLabels) |
| 358 | +} |
| 359 | + |
| 360 | +// GetHelp is part of the metric.Iterable interface. |
| 361 | +func (c *SQLCounter) GetHelp() string { |
| 362 | + return c.g.GetHelp() |
| 363 | +} |
| 364 | + |
| 365 | +// GetMeasurement is part of the metric.Iterable interface. |
| 366 | +func (c *SQLCounter) GetMeasurement() string { |
| 367 | + return c.g.GetMeasurement() |
| 368 | +} |
| 369 | + |
| 370 | +// GetUnit is part of the metric.Iterable interface. |
| 371 | +func (c *SQLCounter) GetUnit() metric.Unit { |
| 372 | + return c.g.GetUnit() |
| 373 | +} |
| 374 | + |
| 375 | +// GetMetadata is part of the metric.Iterable interface. |
| 376 | +func (c *SQLCounter) GetMetadata() metric.Metadata { |
| 377 | + return c.g.GetMetadata() |
| 378 | +} |
| 379 | + |
| 380 | +// Inspect is part of the metric.Iterable interface. |
| 381 | +func (c *SQLCounter) Inspect(f func(interface{})) { |
| 382 | + f(c) |
| 383 | +} |
| 384 | + |
| 385 | +// Inc increments the counter value by i for the given label values. If a |
| 386 | +// counter with the given label values doesn't exist yet, it creates a new |
| 387 | +// counter based on labelConfig and increments it. Inc increments parent metrics |
| 388 | +// irrespective of labelConfig. |
| 389 | +func (c *SQLCounter) Inc(i int64, db, app string) { |
| 390 | + c.g.Inc(i) |
| 391 | + |
| 392 | + var childMetric ChildMetric |
| 393 | + switch c.labelConfig.Load() { |
| 394 | + case LabelConfigDB: |
| 395 | + childMetric = c.getOrAddChild(db) |
| 396 | + case LabelConfigApp: |
| 397 | + childMetric = c.getOrAddChild(app) |
| 398 | + case LabelConfigAppAndDB: |
| 399 | + childMetric = c.getOrAddChild(db, app) |
| 400 | + default: |
| 401 | + return |
| 402 | + } |
| 403 | + childMetric.(*SQLChildCounter).Inc(i) |
| 404 | +} |
| 405 | + |
| 406 | +// SQLChildCounter is a child of a SQLCounter. When metrics are collected by prometheus, |
| 407 | +// each of the children will appear with a distinct label, however, when cockroach |
| 408 | +// internally collects metrics, only the parent is collected. |
| 409 | +type SQLChildCounter struct { |
| 410 | + labelValuesSlice |
| 411 | + value metric.Counter |
| 412 | +} |
| 413 | + |
| 414 | +// ToPrometheusMetric constructs a prometheus metric for this Counter. |
| 415 | +func (s *SQLChildCounter) ToPrometheusMetric() *io_prometheus_client.Metric { |
| 416 | + return &io_prometheus_client.Metric{ |
| 417 | + Counter: &io_prometheus_client.Counter{ |
| 418 | + Value: proto.Float64(float64(s.Value())), |
| 419 | + }, |
| 420 | + } |
| 421 | +} |
| 422 | + |
| 423 | +// Value returns the SQLChildCounter's current value. |
| 424 | +func (s *SQLChildCounter) Value() int64 { |
| 425 | + return s.value.Count() |
| 426 | +} |
| 427 | + |
| 428 | +// Inc increments the SQLChildCounter's value. |
| 429 | +func (s *SQLChildCounter) Inc(i int64) { |
| 430 | + s.value.Inc(i) |
| 431 | +} |
0 commit comments