Component(s)
Loki components
Background
Today loki.Entry stores model.LabelSet as its representation for labels, so that entries can be mutated as they move through the pipeline. But almost nothing in the pipeline actually wants a map.
Most of our loki.source.* components support relabeling and convert between labels.Labels and model.LabelSet, e.g. loki.source.api.
loki.relabel has this exact same pattern, converting in both directions on every cache miss.
loki.write needs to sort these labels in another slice to properly build the required label string before sending to Loki.
Our WAL implementation will convert to labels.Labels when writing and back to model.LabelSet after reading.
loki.process prematurely clones the entry because mutating it in place would be considered unsafe since we can fan out to multiple components. There is already a TODO on that line proposing copy-on-write so the copy only happens on the first stage that needs to modify labels.
And with the new batch structure we want to use for the pipeline changes described in #4953 we could have some potentially expensive clones / comparisons.
Proposal
In our code I have seen this comment about potentially using labels.Labels instead and this other comment around using some kind of copy on write mechanism.
Using labels.Labels would solve all of these issues for us. In places where we need mutations we would use labels.Builder, it's already used in all places where we do relabeling and it would solve the copy on write mentioned in loki.process since it would not allocate anything for labels if nothing has changed. We would also get much cheaper comparisons in our batch implementation since we use stringlabels.
So for this proposal we would change our Entry to
type Entry struct {
Labels labels.Labels
push.Entry
created int64
}
We would need to update the places that do this conversion to just use labels directly. But the biggest change would be in loki.process. In this component we have another representation of entries. We would update this one to look like this:
type Entry struct {
Extracted map[string]any
Builder *labels.Builder
push.Entry
created int64
}
With this structure we would get the copy-on-write semantics for labels, so we would only allocate if a stage actually mutated them. We still need to clone entries since we have other mutable fields like StructuredMetadata, but this would at least be a no-op for labels.
AI disclosure
Tip
React with 👍 if this issue is important to you.
Component(s)
Loki components
Background
Today
loki.Entrystores model.LabelSet as its representation for labels, so that entries can be mutated as they move through the pipeline. But almost nothing in the pipeline actually wants a map.Most of our
loki.source.*components support relabeling and convert betweenlabels.Labelsandmodel.LabelSet, e.g. loki.source.api.loki.relabelhas this exact same pattern, converting in both directions on every cache miss.loki.writeneeds to sort these labels in another slice to properly build the required label string before sending to Loki.Our WAL implementation will convert to
labels.Labelswhen writing and back tomodel.LabelSetafter reading.loki.processprematurely clones the entry because mutating it in place would be considered unsafe since we can fan out to multiple components. There is already aTODOon that line proposing copy-on-write so the copy only happens on the first stage that needs to modify labels.And with the new batch structure we want to use for the pipeline changes described in #4953 we could have some potentially expensive clones / comparisons.
Proposal
In our code I have seen this comment about potentially using
labels.Labelsinstead and this other comment around using some kind of copy on write mechanism.Using
labels.Labelswould solve all of these issues for us. In places where we need mutations we would uselabels.Builder, it's already used in all places where we do relabeling and it would solve the copy on write mentioned inloki.processsince it would not allocate anything for labels if nothing has changed. We would also get much cheaper comparisons in our batch implementation since we usestringlabels.So for this proposal we would change our Entry to
We would need to update the places that do this conversion to just use labels directly. But the biggest change would be in
loki.process. In this component we have another representation of entries. We would update this one to look like this:With this structure we would get the copy-on-write semantics for labels, so we would only allocate if a stage actually mutated them. We still need to clone entries since we have other mutable fields like
StructuredMetadata, but this would at least be a no-op for labels.AI disclosure
Tip
React with 👍 if this issue is important to you.