(app storage.Appender, req *writev2.Request, rs *remoteapi.WriteResponseStats)
| 305 | } |
| 306 | |
| 307 | func (h *writeHandler) appendV2(app storage.Appender, req *writev2.Request, rs *remoteapi.WriteResponseStats) (samplesWithoutMetadata, errHTTPCode int, err error) { |
| 308 | var ( |
| 309 | badRequestErrs []error |
| 310 | outOfOrderExemplarErrs, samplesWithInvalidLabels int |
| 311 | |
| 312 | b = labels.NewScratchBuilder(0) |
| 313 | ) |
| 314 | for _, ts := range req.Timeseries { |
| 315 | ls, err := ts.ToLabels(&b, req.Symbols) |
| 316 | if err != nil { |
| 317 | badRequestErrs = append(badRequestErrs, fmt.Errorf("parsing labels for series %v: %w", ts.LabelsRefs, err)) |
| 318 | samplesWithInvalidLabels += len(ts.Samples) + len(ts.Histograms) |
| 319 | continue |
| 320 | } |
| 321 | |
| 322 | m, err := ts.ToMetadata(req.Symbols) |
| 323 | if err != nil { |
| 324 | badRequestErrs = append(badRequestErrs, fmt.Errorf("parsing metadata for series %v: %w", ts.LabelsRefs, err)) |
| 325 | continue |
| 326 | } |
| 327 | if h.enableTypeAndUnitLabels && (m.Type != model.MetricTypeUnknown || m.Unit != "") { |
| 328 | slb := labels.NewScratchBuilder(ls.Len() + 2) // +2 for __type__ and __unit__ |
| 329 | ls.Range(func(l labels.Label) { |
| 330 | // Skip __type__ and __unit__ labels if they exist in the incoming labels. |
| 331 | // They will be added from metadata to avoid duplicates. |
| 332 | if l.Name != model.MetricTypeLabel && l.Name != model.MetricUnitLabel { |
| 333 | slb.Add(l.Name, l.Value) |
| 334 | } |
| 335 | }) |
| 336 | schema.Metadata{Type: m.Type, Unit: m.Unit}.AddToLabels(&slb) |
| 337 | slb.Sort() |
| 338 | ls = slb.Labels() |
| 339 | } |
| 340 | |
| 341 | // Validate series labels early. |
| 342 | // NOTE(bwplotka): While spec allows UTF-8, Prometheus Receiver may impose |
| 343 | // specific limits and follow https://prometheus.io/docs/specs/remote_write_spec_2_0/#invalid-samples case. |
| 344 | if !ls.Has(labels.MetricName) || !ls.IsValid(model.UTF8Validation) { |
| 345 | badRequestErrs = append(badRequestErrs, fmt.Errorf("invalid metric name or labels, got %v", ls.String())) |
| 346 | samplesWithInvalidLabels += len(ts.Samples) + len(ts.Histograms) |
| 347 | continue |
| 348 | } else if duplicateLabel, hasDuplicate := ls.HasDuplicateLabelNames(); hasDuplicate { |
| 349 | badRequestErrs = append(badRequestErrs, fmt.Errorf("invalid labels for series, labels %v, duplicated label %s", ls.String(), duplicateLabel)) |
| 350 | samplesWithInvalidLabels += len(ts.Samples) + len(ts.Histograms) |
| 351 | continue |
| 352 | } |
| 353 | |
| 354 | // Validate that the TimeSeries has at least one sample or histogram. |
| 355 | if len(ts.Samples) == 0 && len(ts.Histograms) == 0 { |
| 356 | badRequestErrs = append(badRequestErrs, fmt.Errorf("TimeSeries must contain at least one sample or histogram for series %v", ls.String())) |
| 357 | continue |
| 358 | } |
| 359 | |
| 360 | allSamplesSoFar := rs.AllSamples() |
| 361 | var ref storage.SeriesRef |
| 362 | for _, s := range ts.Samples { |
| 363 | if h.ingestSTZeroSample && s.StartTimestamp != 0 && s.Timestamp != 0 { |
| 364 | ref, err = app.AppendSTZeroSample(ref, ls, s.Timestamp, s.StartTimestamp) |
no test coverage detected