Skip to content

Commit a962edb

Browse files
feat(loki): include structured_metadata size while asserting rate limit (#14571)
Signed-off-by: Vladyslav Diachenko <[email protected]>
1 parent 7965722 commit a962edb

File tree

14 files changed

+127
-98
lines changed

14 files changed

+127
-98
lines changed

docs/sources/get-started/labels/structured-metadata.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ See the [Promtail: Structured metadata stage](https://grafana.com/docs/loki/<LOK
3737
With Loki version 1.2.0, support for structured metadata has been added to the Logstash output plugin. For more information, see [logstash](https://grafana.com/docs/loki/<LOKI_VERSION>/send-data/logstash/).
3838

3939
{{% admonition type="warning" %}}
40-
There are defaults for how much structured metadata can be attached per log line.
40+
Structured metadata size is taken into account while asserting ingestion rate limiting.
41+
Along with that, there are separate limits on how much structured metadata can be attached per log line.
4142
```
4243
# Maximum size accepted for structured metadata per log line.
4344
# CLI flag: -limits.max-structured-metadata-size

docs/sources/operations/request-validation-rate-limits.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ It is recommended that Loki operators set up alerts or dashboards with these met
1616

1717
### Terminology
1818

19-
- **sample**: a log line
19+
- **sample**: a log line with [structured metadata]({{< relref "../get-started/labels/structured-metadata" >}})
2020
- **stream**: samples with a unique combination of labels
2121
- **active stream**: streams that are present in the ingesters - these have recently received log lines within the `chunk_idle_period` period (default: 30m)
2222

docs/sources/shared/configuration.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -3260,7 +3260,8 @@ The `limits_config` block configures global and per-tenant limits in Loki. The v
32603260
# CLI flag: -distributor.ingestion-rate-limit-strategy
32613261
[ingestion_rate_strategy: <string> | default = "global"]
32623262
3263-
# Per-user ingestion rate limit in sample size per second. Units in MB.
3263+
# Per-user ingestion rate limit in sample size per second. Sample size includes
3264+
# size of the logs line and the size of structured metadata labels. Units in MB.
32643265
# CLI flag: -distributor.ingestion-rate-limit-mb
32653266
[ingestion_rate_mb: <float> | default = 4]
32663267

pkg/distributor/distributor.go

+4-10
Original file line numberDiff line numberDiff line change
@@ -471,11 +471,8 @@ func (d *Distributor) Push(ctx context.Context, req *logproto.PushRequest) (*log
471471
d.writeFailuresManager.Log(tenantID, err)
472472
validationErrors.Add(err)
473473
validation.DiscardedSamples.WithLabelValues(validation.InvalidLabels, tenantID).Add(float64(len(stream.Entries)))
474-
bytes := 0
475-
for _, e := range stream.Entries {
476-
bytes += len(e.Line)
477-
}
478-
validation.DiscardedBytes.WithLabelValues(validation.InvalidLabels, tenantID).Add(float64(bytes))
474+
discardedBytes := util.EntriesTotalSize(stream.Entries)
475+
validation.DiscardedBytes.WithLabelValues(validation.InvalidLabels, tenantID).Add(float64(discardedBytes))
479476
continue
480477
}
481478

@@ -527,7 +524,7 @@ func (d *Distributor) Push(ctx context.Context, req *logproto.PushRequest) (*log
527524
}
528525

529526
n++
530-
validatedLineSize += len(entry.Line)
527+
validatedLineSize += util.EntryTotalSize(&entry)
531528
validatedLineCount++
532529
pushSize += len(entry.Line)
533530
}
@@ -706,10 +703,7 @@ func (d *Distributor) trackDiscardedData(
706703
continue
707704
}
708705

709-
discardedStreamBytes := 0
710-
for _, e := range stream.Entries {
711-
discardedStreamBytes += len(e.Line)
712-
}
706+
discardedStreamBytes := util.EntriesTotalSize(stream.Entries)
713707

714708
if d.usageTracker != nil {
715709
d.usageTracker.DiscardedBytesAdd(ctx, tenantID, reason, lbs, float64(discardedStreamBytes))

pkg/distributor/distributor_test.go

+27-24
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"testing"
1313
"time"
1414

15+
"github.com/c2h5oh/datasize"
1516
"github.com/go-kit/log"
1617
"github.com/grafana/dskit/flagext"
1718
"github.com/grafana/dskit/httpgrpc"
@@ -54,7 +55,9 @@ var (
5455
)
5556

5657
func TestDistributor(t *testing.T) {
57-
ingestionRateLimit := 0.000096 // 100 Bytes/s limit
58+
lineSize := 10
59+
ingestionRateLimit := datasize.ByteSize(400)
60+
ingestionRateLimitMB := ingestionRateLimit.MBytes() // 400 Bytes/s limit
5861

5962
for i, tc := range []struct {
6063
lines int
@@ -72,7 +75,7 @@ func TestDistributor(t *testing.T) {
7275
{
7376
lines: 100,
7477
streams: 1,
75-
expectedErrors: []error{httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 100, 100, 1000)},
78+
expectedErrors: []error{httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", ingestionRateLimit, 100, 100*lineSize)},
7679
},
7780
{
7881
lines: 100,
@@ -104,15 +107,15 @@ func TestDistributor(t *testing.T) {
104107
t.Run(fmt.Sprintf("[%d](lines=%v)", i, tc.lines), func(t *testing.T) {
105108
limits := &validation.Limits{}
106109
flagext.DefaultValues(limits)
107-
limits.IngestionRateMB = ingestionRateLimit
108-
limits.IngestionBurstSizeMB = ingestionRateLimit
110+
limits.IngestionRateMB = ingestionRateLimitMB
111+
limits.IngestionBurstSizeMB = ingestionRateLimitMB
109112
limits.MaxLineSize = fe.ByteSize(tc.maxLineSize)
110113

111114
distributors, _ := prepare(t, 1, 5, limits, nil)
112115

113116
var request logproto.PushRequest
114117
for i := 0; i < tc.streams; i++ {
115-
req := makeWriteRequest(tc.lines, 10)
118+
req := makeWriteRequest(tc.lines, lineSize)
116119
request.Streams = append(request.Streams, req.Streams[0])
117120
}
118121

@@ -1178,37 +1181,37 @@ func TestDistributor_PushIngestionRateLimiter(t *testing.T) {
11781181
"local strategy: limit should be set to each distributor": {
11791182
distributors: 2,
11801183
ingestionRateStrategy: validation.LocalIngestionRateStrategy,
1181-
ingestionRateMB: 10 * (1.0 / float64(bytesInMB)),
1182-
ingestionBurstSizeMB: 10 * (1.0 / float64(bytesInMB)),
1184+
ingestionRateMB: datasize.ByteSize(100).MBytes(),
1185+
ingestionBurstSizeMB: datasize.ByteSize(100).MBytes(),
11831186
pushes: []testPush{
1184-
{bytes: 5, expectedError: nil},
1185-
{bytes: 6, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 10, 1, 6)},
1186-
{bytes: 5, expectedError: nil},
1187-
{bytes: 1, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 10, 1, 1)},
1187+
{bytes: 50, expectedError: nil},
1188+
{bytes: 60, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 100, 1, 60)},
1189+
{bytes: 50, expectedError: nil},
1190+
{bytes: 40, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 100, 1, 40)},
11881191
},
11891192
},
11901193
"global strategy: limit should be evenly shared across distributors": {
11911194
distributors: 2,
11921195
ingestionRateStrategy: validation.GlobalIngestionRateStrategy,
1193-
ingestionRateMB: 10 * (1.0 / float64(bytesInMB)),
1194-
ingestionBurstSizeMB: 5 * (1.0 / float64(bytesInMB)),
1196+
ingestionRateMB: datasize.ByteSize(200).MBytes(),
1197+
ingestionBurstSizeMB: datasize.ByteSize(100).MBytes(),
11951198
pushes: []testPush{
1196-
{bytes: 3, expectedError: nil},
1197-
{bytes: 3, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 5, 1, 3)},
1198-
{bytes: 2, expectedError: nil},
1199-
{bytes: 1, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 5, 1, 1)},
1199+
{bytes: 60, expectedError: nil},
1200+
{bytes: 50, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 100, 1, 50)},
1201+
{bytes: 40, expectedError: nil},
1202+
{bytes: 30, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 100, 1, 30)},
12001203
},
12011204
},
12021205
"global strategy: burst should set to each distributor": {
12031206
distributors: 2,
12041207
ingestionRateStrategy: validation.GlobalIngestionRateStrategy,
1205-
ingestionRateMB: 10 * (1.0 / float64(bytesInMB)),
1206-
ingestionBurstSizeMB: 20 * (1.0 / float64(bytesInMB)),
1208+
ingestionRateMB: datasize.ByteSize(100).MBytes(),
1209+
ingestionBurstSizeMB: datasize.ByteSize(200).MBytes(),
12071210
pushes: []testPush{
1208-
{bytes: 15, expectedError: nil},
1209-
{bytes: 6, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 5, 1, 6)},
1210-
{bytes: 5, expectedError: nil},
1211-
{bytes: 1, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 5, 1, 1)},
1211+
{bytes: 150, expectedError: nil},
1212+
{bytes: 60, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 50, 1, 60)},
1213+
{bytes: 50, expectedError: nil},
1214+
{bytes: 30, expectedError: httpgrpc.Errorf(http.StatusTooManyRequests, validation.RateLimitedErrorMsg, "test", 50, 1, 30)},
12121215
},
12131216
},
12141217
}
@@ -1227,8 +1230,8 @@ func TestDistributor_PushIngestionRateLimiter(t *testing.T) {
12271230
response, err := distributors[0].Push(ctx, request)
12281231

12291232
if push.expectedError == nil {
1233+
assert.NoError(t, err)
12301234
assert.Equal(t, success, response)
1231-
assert.Nil(t, err)
12321235
} else {
12331236
assert.Nil(t, response)
12341237
assert.Equal(t, push.expectedError, err)

pkg/distributor/validator.go

+19-24
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/grafana/loki/v3/pkg/loghttp/push"
1313
"github.com/grafana/loki/v3/pkg/logproto"
14+
"github.com/grafana/loki/v3/pkg/util"
1415
"github.com/grafana/loki/v3/pkg/validation"
1516
)
1617

@@ -82,25 +83,28 @@ func (v Validator) getValidationContextForTime(now time.Time, userID string) val
8283
func (v Validator) ValidateEntry(ctx context.Context, vCtx validationContext, labels labels.Labels, entry logproto.Entry) error {
8384
ts := entry.Timestamp.UnixNano()
8485
validation.LineLengthHist.Observe(float64(len(entry.Line)))
86+
structuredMetadataCount := len(entry.StructuredMetadata)
87+
structuredMetadataSizeBytes := util.StructuredMetadataSize(entry.StructuredMetadata)
88+
entrySize := float64(len(entry.Line) + structuredMetadataSizeBytes)
8589

8690
if vCtx.rejectOldSample && ts < vCtx.rejectOldSampleMaxAge {
8791
// Makes time string on the error message formatted consistently.
8892
formatedEntryTime := entry.Timestamp.Format(timeFormat)
8993
formatedRejectMaxAgeTime := time.Unix(0, vCtx.rejectOldSampleMaxAge).Format(timeFormat)
9094
validation.DiscardedSamples.WithLabelValues(validation.GreaterThanMaxSampleAge, vCtx.userID).Inc()
91-
validation.DiscardedBytes.WithLabelValues(validation.GreaterThanMaxSampleAge, vCtx.userID).Add(float64(len(entry.Line)))
95+
validation.DiscardedBytes.WithLabelValues(validation.GreaterThanMaxSampleAge, vCtx.userID).Add(entrySize)
9296
if v.usageTracker != nil {
93-
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.GreaterThanMaxSampleAge, labels, float64(len(entry.Line)))
97+
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.GreaterThanMaxSampleAge, labels, entrySize)
9498
}
9599
return fmt.Errorf(validation.GreaterThanMaxSampleAgeErrorMsg, labels, formatedEntryTime, formatedRejectMaxAgeTime)
96100
}
97101

98102
if ts > vCtx.creationGracePeriod {
99103
formatedEntryTime := entry.Timestamp.Format(timeFormat)
100104
validation.DiscardedSamples.WithLabelValues(validation.TooFarInFuture, vCtx.userID).Inc()
101-
validation.DiscardedBytes.WithLabelValues(validation.TooFarInFuture, vCtx.userID).Add(float64(len(entry.Line)))
105+
validation.DiscardedBytes.WithLabelValues(validation.TooFarInFuture, vCtx.userID).Add(entrySize)
102106
if v.usageTracker != nil {
103-
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.TooFarInFuture, labels, float64(len(entry.Line)))
107+
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.TooFarInFuture, labels, entrySize)
104108
}
105109
return fmt.Errorf(validation.TooFarInFutureErrorMsg, labels, formatedEntryTime)
106110
}
@@ -111,43 +115,37 @@ func (v Validator) ValidateEntry(ctx context.Context, vCtx validationContext, la
111115
// but the upstream cortex_validation pkg uses it, so we keep this
112116
// for parity.
113117
validation.DiscardedSamples.WithLabelValues(validation.LineTooLong, vCtx.userID).Inc()
114-
validation.DiscardedBytes.WithLabelValues(validation.LineTooLong, vCtx.userID).Add(float64(len(entry.Line)))
118+
validation.DiscardedBytes.WithLabelValues(validation.LineTooLong, vCtx.userID).Add(entrySize)
115119
if v.usageTracker != nil {
116-
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.LineTooLong, labels, float64(len(entry.Line)))
120+
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.LineTooLong, labels, entrySize)
117121
}
118122
return fmt.Errorf(validation.LineTooLongErrorMsg, maxSize, labels, len(entry.Line))
119123
}
120124

121-
if len(entry.StructuredMetadata) > 0 {
125+
if structuredMetadataCount > 0 {
122126
if !vCtx.allowStructuredMetadata {
123127
validation.DiscardedSamples.WithLabelValues(validation.DisallowedStructuredMetadata, vCtx.userID).Inc()
124-
validation.DiscardedBytes.WithLabelValues(validation.DisallowedStructuredMetadata, vCtx.userID).Add(float64(len(entry.Line)))
128+
validation.DiscardedBytes.WithLabelValues(validation.DisallowedStructuredMetadata, vCtx.userID).Add(entrySize)
125129
if v.usageTracker != nil {
126-
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.DisallowedStructuredMetadata, labels, float64(len(entry.Line)))
130+
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.DisallowedStructuredMetadata, labels, entrySize)
127131
}
128132
return fmt.Errorf(validation.DisallowedStructuredMetadataErrorMsg, labels)
129133
}
130134

131-
var structuredMetadataSizeBytes, structuredMetadataCount int
132-
for _, metadata := range entry.StructuredMetadata {
133-
structuredMetadataSizeBytes += len(metadata.Name) + len(metadata.Value)
134-
structuredMetadataCount++
135-
}
136-
137135
if maxSize := vCtx.maxStructuredMetadataSize; maxSize != 0 && structuredMetadataSizeBytes > maxSize {
138136
validation.DiscardedSamples.WithLabelValues(validation.StructuredMetadataTooLarge, vCtx.userID).Inc()
139-
validation.DiscardedBytes.WithLabelValues(validation.StructuredMetadataTooLarge, vCtx.userID).Add(float64(len(entry.Line)))
137+
validation.DiscardedBytes.WithLabelValues(validation.StructuredMetadataTooLarge, vCtx.userID).Add(entrySize)
140138
if v.usageTracker != nil {
141-
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.StructuredMetadataTooLarge, labels, float64(len(entry.Line)))
139+
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.StructuredMetadataTooLarge, labels, entrySize)
142140
}
143141
return fmt.Errorf(validation.StructuredMetadataTooLargeErrorMsg, labels, structuredMetadataSizeBytes, vCtx.maxStructuredMetadataSize)
144142
}
145143

146144
if maxCount := vCtx.maxStructuredMetadataCount; maxCount != 0 && structuredMetadataCount > maxCount {
147145
validation.DiscardedSamples.WithLabelValues(validation.StructuredMetadataTooMany, vCtx.userID).Inc()
148-
validation.DiscardedBytes.WithLabelValues(validation.StructuredMetadataTooMany, vCtx.userID).Add(float64(len(entry.Line)))
146+
validation.DiscardedBytes.WithLabelValues(validation.StructuredMetadataTooMany, vCtx.userID).Add(entrySize)
149147
if v.usageTracker != nil {
150-
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.StructuredMetadataTooMany, labels, float64(len(entry.Line)))
148+
v.usageTracker.DiscardedBytesAdd(ctx, vCtx.userID, validation.StructuredMetadataTooMany, labels, entrySize)
151149
}
152150
return fmt.Errorf(validation.StructuredMetadataTooManyErrorMsg, labels, structuredMetadataCount, vCtx.maxStructuredMetadataCount)
153151
}
@@ -207,10 +205,7 @@ func (v Validator) ShouldBlockIngestion(ctx validationContext, now time.Time) (b
207205
}
208206

209207
func updateMetrics(reason, userID string, stream logproto.Stream) {
210-
validation.DiscardedSamples.WithLabelValues(reason, userID).Inc()
211-
bytes := 0
212-
for _, e := range stream.Entries {
213-
bytes += len(e.Line)
214-
}
208+
validation.DiscardedSamples.WithLabelValues(reason, userID).Add(float64(len(stream.Entries)))
209+
bytes := util.EntriesTotalSize(stream.Entries)
215210
validation.DiscardedBytes.WithLabelValues(reason, userID).Add(float64(bytes))
216211
}

pkg/ingester-rf1/instance.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/grafana/loki/v3/pkg/runtime"
2525
"github.com/grafana/loki/v3/pkg/storage/config"
2626
"github.com/grafana/loki/v3/pkg/storage/wal"
27+
"github.com/grafana/loki/v3/pkg/util"
2728
"github.com/grafana/loki/v3/pkg/util/constants"
2829
util_log "github.com/grafana/loki/v3/pkg/util/log"
2930
"github.com/grafana/loki/v3/pkg/validation"
@@ -269,10 +270,7 @@ func (i *instance) onStreamCreationError(ctx context.Context, pushReqStream logp
269270
}
270271

271272
validation.DiscardedSamples.WithLabelValues(validation.StreamLimit, i.instanceID).Add(float64(len(pushReqStream.Entries)))
272-
bytes := 0
273-
for _, e := range pushReqStream.Entries {
274-
bytes += len(e.Line)
275-
}
273+
bytes := util.EntriesTotalSize(pushReqStream.Entries)
276274
validation.DiscardedBytes.WithLabelValues(validation.StreamLimit, i.instanceID).Add(float64(bytes))
277275
if i.customStreamsTracker != nil {
278276
i.customStreamsTracker.DiscardedBytesAdd(ctx, i.instanceID, validation.StreamLimit, labels, float64(bytes))

pkg/ingester-rf1/stream.go

+11-9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/grafana/loki/v3/pkg/loghttp/push"
1919
"github.com/grafana/loki/v3/pkg/logproto"
2020
"github.com/grafana/loki/v3/pkg/storage/wal"
21+
"github.com/grafana/loki/v3/pkg/util"
2122
"github.com/grafana/loki/v3/pkg/util/flagext"
2223
"github.com/grafana/loki/v3/pkg/validation"
2324
)
@@ -245,15 +246,15 @@ func (s *stream) validateEntries(ctx context.Context, entries []logproto.Entry,
245246
continue
246247
}
247248

248-
lineBytes := len(entries[i].Line)
249-
totalBytes += lineBytes
249+
entryBytes := util.EntryTotalSize(&entries[i])
250+
totalBytes += entryBytes
250251

251252
now := time.Now()
252-
if !rateLimitWholeStream && !s.limiter.AllowN(now, len(entries[i].Line)) {
253-
failedEntriesWithError = append(failedEntriesWithError, entryWithError{&entries[i], &validation.ErrStreamRateLimit{RateLimit: flagext.ByteSize(limit), Labels: s.labelsString, Bytes: flagext.ByteSize(lineBytes)}})
253+
if !rateLimitWholeStream && !s.limiter.AllowN(now, entryBytes) {
254+
failedEntriesWithError = append(failedEntriesWithError, entryWithError{&entries[i], &validation.ErrStreamRateLimit{RateLimit: flagext.ByteSize(limit), Labels: s.labelsString, Bytes: flagext.ByteSize(entryBytes)}})
254255
s.writeFailures.Log(s.tenant, failedEntriesWithError[len(failedEntriesWithError)-1].e)
255256
rateLimitedSamples++
256-
rateLimitedBytes += lineBytes
257+
rateLimitedBytes += entryBytes
257258
continue
258259
}
259260

@@ -263,11 +264,11 @@ func (s *stream) validateEntries(ctx context.Context, entries []logproto.Entry,
263264
failedEntriesWithError = append(failedEntriesWithError, entryWithError{&entries[i], chunkenc.ErrTooFarBehind(entries[i].Timestamp, cutoff)})
264265
s.writeFailures.Log(s.tenant, fmt.Errorf("%w for stream %s", failedEntriesWithError[len(failedEntriesWithError)-1].e, s.labels))
265266
outOfOrderSamples++
266-
outOfOrderBytes += lineBytes
267+
outOfOrderBytes += entryBytes
267268
continue
268269
}
269270

270-
validBytes += lineBytes
271+
validBytes += entryBytes
271272

272273
lastLine.ts = entries[i].Timestamp
273274
lastLine.content = entries[i].Line
@@ -287,8 +288,9 @@ func (s *stream) validateEntries(ctx context.Context, entries []logproto.Entry,
287288
rateLimitedSamples = len(toStore)
288289
failedEntriesWithError = make([]entryWithError, 0, len(toStore))
289290
for i := 0; i < len(toStore); i++ {
290-
failedEntriesWithError = append(failedEntriesWithError, entryWithError{toStore[i], &validation.ErrStreamRateLimit{RateLimit: flagext.ByteSize(limit), Labels: s.labelsString, Bytes: flagext.ByteSize(len(toStore[i].Line))}})
291-
rateLimitedBytes += len(toStore[i].Line)
291+
entryTotalSize := util.EntryTotalSize(toStore[i])
292+
failedEntriesWithError = append(failedEntriesWithError, entryWithError{toStore[i], &validation.ErrStreamRateLimit{RateLimit: flagext.ByteSize(limit), Labels: s.labelsString, Bytes: flagext.ByteSize(entryTotalSize)}})
293+
rateLimitedBytes += entryTotalSize
292294
}
293295
}
294296

pkg/ingester/instance.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,7 @@ func (i *instance) onStreamCreationError(ctx context.Context, pushReqStream logp
336336
}
337337

338338
validation.DiscardedSamples.WithLabelValues(validation.StreamLimit, i.instanceID).Add(float64(len(pushReqStream.Entries)))
339-
bytes := 0
340-
for _, e := range pushReqStream.Entries {
341-
bytes += len(e.Line)
342-
}
339+
bytes := util.EntriesTotalSize(pushReqStream.Entries)
343340
validation.DiscardedBytes.WithLabelValues(validation.StreamLimit, i.instanceID).Add(float64(bytes))
344341
if i.customStreamsTracker != nil {
345342
i.customStreamsTracker.DiscardedBytesAdd(ctx, i.instanceID, validation.StreamLimit, labels, float64(bytes))

0 commit comments

Comments
 (0)