forked from grafana/loki
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support categorized labels in Tailing (grafana#11079)
**What this PR does / why we need it**: This is a follow-up PR for grafana#10419 adding support for tailing. I tested it on a dev cell and works fine. <img width="1296" alt="image" src="https://github.com/grafana/loki/assets/8354290/6177e0ca-02ce-48cd-a17f-0739dc3caa0a"> **Note**: With these changes, the JSON marshal unmarshal functions for the tail are no longer used ([example][1]) so I think we can remove them. Also, the new Tail response is no longer used, so we can also make it an alias to the _legacy_ one. Let's do it on a follow-up PR to avoid making this one bigger. [1]: https://github.com/grafana/loki/blob/52a3f16039dd5ff655fc3681257d99794f620ec4/pkg/loghttp/entry.go#L210-L238
- Loading branch information
1 parent
194aaa4
commit 925b5e3
Showing
17 changed files
with
803 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package iter | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/prometheus/prometheus/model/labels" | ||
|
||
"github.com/grafana/loki/pkg/logproto" | ||
"github.com/grafana/loki/pkg/logql/syntax" | ||
) | ||
|
||
type categorizeLabelsIterator struct { | ||
EntryIterator | ||
currEntry logproto.Entry | ||
currStreamLabels string | ||
currHash uint64 | ||
currErr error | ||
} | ||
|
||
func NewCategorizeLabelsIterator(wrap EntryIterator) EntryIterator { | ||
return &categorizeLabelsIterator{ | ||
EntryIterator: wrap, | ||
} | ||
} | ||
|
||
func (c *categorizeLabelsIterator) Next() bool { | ||
if !c.EntryIterator.Next() { | ||
return false | ||
} | ||
|
||
c.currEntry = c.Entry() | ||
if len(c.currEntry.StructuredMetadata) == 0 && len(c.currEntry.Parsed) == 0 { | ||
c.currStreamLabels = c.EntryIterator.Labels() | ||
c.currHash = c.EntryIterator.StreamHash() | ||
return true | ||
} | ||
|
||
// We need to remove the structured metadata labels and parsed labels from the stream labels. | ||
streamLabels := c.EntryIterator.Labels() | ||
lbls, err := syntax.ParseLabels(streamLabels) | ||
if err != nil { | ||
c.currErr = fmt.Errorf("failed to parse series labels to categorize labels: %w", err) | ||
return false | ||
} | ||
|
||
builder := labels.NewBuilder(lbls) | ||
for _, label := range c.currEntry.StructuredMetadata { | ||
builder.Del(label.Name) | ||
} | ||
for _, label := range c.currEntry.Parsed { | ||
builder.Del(label.Name) | ||
} | ||
|
||
newLabels := builder.Labels() | ||
c.currStreamLabels = newLabels.String() | ||
c.currHash = newLabels.Hash() | ||
|
||
return true | ||
} | ||
|
||
func (c *categorizeLabelsIterator) Error() error { | ||
return c.currErr | ||
} | ||
|
||
func (c *categorizeLabelsIterator) Labels() string { | ||
return c.currStreamLabels | ||
} | ||
|
||
func (c *categorizeLabelsIterator) StreamHash() uint64 { | ||
return c.currHash | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package iter | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/prometheus/prometheus/model/labels" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/grafana/loki/pkg/logproto" | ||
) | ||
|
||
func TestNewCategorizeLabelsIterator(t *testing.T) { | ||
for _, tc := range []struct { | ||
name string | ||
inner EntryIterator | ||
expectedStreams []logproto.Stream | ||
}{ | ||
{ | ||
name: "no structured metadata nor parsed labels", | ||
inner: NewSortEntryIterator([]EntryIterator{ | ||
NewStreamIterator(logproto.Stream{ | ||
Labels: labels.FromStrings("namespace", "default").String(), | ||
Entries: []logproto.Entry{ | ||
{ | ||
Timestamp: time.Unix(0, 1), | ||
Line: "foo=1", | ||
}, | ||
{ | ||
Timestamp: time.Unix(0, 2), | ||
Line: "foo=2", | ||
}, | ||
}, | ||
}), | ||
}, logproto.FORWARD), | ||
expectedStreams: []logproto.Stream{ | ||
{ | ||
Labels: labels.FromStrings("namespace", "default").String(), | ||
Entries: []logproto.Entry{ | ||
{ | ||
Timestamp: time.Unix(0, 1), | ||
Line: "foo=1", | ||
}, | ||
{ | ||
Timestamp: time.Unix(0, 2), | ||
Line: "foo=2", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "structured metadata and parsed labels", | ||
inner: NewSortEntryIterator([]EntryIterator{ | ||
NewStreamIterator(logproto.Stream{ | ||
Labels: labels.FromStrings("namespace", "default").String(), | ||
Entries: []logproto.Entry{ | ||
{ | ||
Timestamp: time.Unix(0, 1), | ||
Line: "foo=1", | ||
}, | ||
}, | ||
}), | ||
NewStreamIterator(logproto.Stream{ | ||
Labels: labels.FromStrings("namespace", "default", "traceID", "123").String(), | ||
Entries: []logproto.Entry{ | ||
{ | ||
Timestamp: time.Unix(0, 2), | ||
Line: "foo=2", | ||
StructuredMetadata: logproto.FromLabelsToLabelAdapters(labels.FromStrings("traceID", "123")), | ||
}, | ||
}, | ||
}), | ||
NewStreamIterator(logproto.Stream{ | ||
Labels: labels.FromStrings("namespace", "default", "foo", "3").String(), | ||
Entries: []logproto.Entry{ | ||
{ | ||
Timestamp: time.Unix(0, 3), | ||
Line: "foo=3", | ||
Parsed: logproto.FromLabelsToLabelAdapters(labels.FromStrings("foo", "3")), | ||
}, | ||
}, | ||
}), | ||
NewStreamIterator(logproto.Stream{ | ||
Labels: labels.FromStrings("namespace", "default", "traceID", "123", "foo", "4").String(), | ||
Entries: []logproto.Entry{ | ||
{ | ||
Timestamp: time.Unix(0, 4), | ||
Line: "foo=4", | ||
StructuredMetadata: logproto.FromLabelsToLabelAdapters(labels.FromStrings("traceID", "123")), | ||
Parsed: logproto.FromLabelsToLabelAdapters(labels.FromStrings("foo", "4")), | ||
}, | ||
}, | ||
}), | ||
}, logproto.FORWARD), | ||
expectedStreams: []logproto.Stream{ | ||
{ | ||
Labels: labels.FromStrings("namespace", "default").String(), | ||
Entries: []logproto.Entry{ | ||
{ | ||
Timestamp: time.Unix(0, 1), | ||
Line: "foo=1", | ||
}, | ||
{ | ||
Timestamp: time.Unix(0, 2), | ||
Line: "foo=2", | ||
StructuredMetadata: logproto.FromLabelsToLabelAdapters(labels.FromStrings("traceID", "123")), | ||
}, | ||
{ | ||
Timestamp: time.Unix(0, 3), | ||
Line: "foo=3", | ||
Parsed: logproto.FromLabelsToLabelAdapters(labels.FromStrings("foo", "3")), | ||
}, | ||
{ | ||
Timestamp: time.Unix(0, 4), | ||
Line: "foo=4", | ||
StructuredMetadata: logproto.FromLabelsToLabelAdapters(labels.FromStrings("traceID", "123")), | ||
Parsed: logproto.FromLabelsToLabelAdapters(labels.FromStrings("foo", "4")), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
itr := NewCategorizeLabelsIterator(tc.inner) | ||
|
||
streamsEntries := make(map[string][]logproto.Entry) | ||
for itr.Next() { | ||
streamsEntries[itr.Labels()] = append(streamsEntries[itr.Labels()], itr.Entry()) | ||
require.NoError(t, itr.Error()) | ||
} | ||
|
||
var streams []logproto.Stream | ||
for lbls, entries := range streamsEntries { | ||
streams = append(streams, logproto.Stream{ | ||
Labels: lbls, | ||
Entries: entries, | ||
}) | ||
} | ||
|
||
require.ElementsMatch(t, tc.expectedStreams, streams) | ||
}) | ||
} | ||
} |
Oops, something went wrong.