Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loki HTTP/JSON Model Layer #1022

Merged
merged 59 commits into from
Sep 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
fe23eff
First pass data model
joe-elliott Sep 13, 2019
cd2dab3
Use prom model b/c we're serializing promql objects
joe-elliott Sep 13, 2019
1ba0d7f
Added legacy query support and tests
joe-elliott Sep 14, 2019
80d4aba
Added legacy label test
joe-elliott Sep 15, 2019
bb72d46
Added tail response marshalling and tests
joe-elliott Sep 15, 2019
e39f920
Fixed marshallers and test
joe-elliott Sep 15, 2019
26e9915
Expanded legacy test cases
joe-elliott Sep 15, 2019
528b08c
Dropped streams nano test
joe-elliott Sep 15, 2019
9201f03
First pass v1 new objects
joe-elliott Sep 15, 2019
38ae5e9
Added failing tail response tests
joe-elliott Sep 15, 2019
64f0a86
Added failing tailresponse test
joe-elliott Sep 15, 2019
ab342ef
Partial v1 tests
joe-elliott Sep 15, 2019
fee712f
Improved legacy labels test
joe-elliott Sep 15, 2019
d9efb3a
Improved legacy query tests
joe-elliott Sep 15, 2019
5f03769
Moved all legacy tests to new method
joe-elliott Sep 15, 2019
8127ba5
Added v1 tests and fixed stream marshalling bug
joe-elliott Sep 15, 2019
a57f76e
First pass new Model
joe-elliott Sep 16, 2019
1266c95
Added vector test
joe-elliott Sep 16, 2019
cc4fc5f
Added matrix tests
joe-elliott Sep 16, 2019
96590d1
Added conversions for all things except tailed responses
joe-elliott Sep 16, 2019
0833db7
Fixed mixed case issues
joe-elliott Sep 16, 2019
d109681
Fixed tail marshalling
joe-elliott Sep 16, 2019
0769c9b
Removed unused testStream
joe-elliott Sep 16, 2019
a37fec1
Moved TailResponse to loghttp
joe-elliott Sep 16, 2019
60354ca
Removed legacy tailresponse objects in favor of actual legacy tailres…
joe-elliott Sep 16, 2019
1f1063a
Updated v1 methods to take legacy tail objects
joe-elliott Sep 16, 2019
ce75247
Cleaned up tests. Added some comments
joe-elliott Sep 16, 2019
d1c9e68
Versioned tail endpoint
joe-elliott Sep 16, 2019
a9a8d41
Improved readability on loghttp packages in http.go
joe-elliott Sep 17, 2019
ac719d2
Removed new as a var name
joe-elliott Sep 17, 2019
a13bfa1
Started all error messages with lowercase alerts
joe-elliott Sep 17, 2019
7865163
new => ret
joe-elliott Sep 17, 2019
ad18ea7
Added comments on exported methods
joe-elliott Sep 17, 2019
fff21ad
Removed two personal notes
joe-elliott Sep 17, 2019
493147e
Changed legacy package name to loghttp
joe-elliott Sep 19, 2019
a8eb82e
Moved and renamed loghttp v1 package
joe-elliott Sep 19, 2019
4c51e24
Moved marshalling code out of model
joe-elliott Sep 19, 2019
bee682a
Added package comments
joe-elliott Sep 19, 2019
22703e5
Added legacy testing
joe-elliott Sep 19, 2019
a6a174a
Changed DroppedStream slice to value type for consistency
joe-elliott Sep 19, 2019
e9af745
gofmt'ed test files
joe-elliott Sep 19, 2019
7174fe7
Cleaned up linting issues
joe-elliott Sep 19, 2019
f4683ea
Minor comment cleanup
joe-elliott Sep 19, 2019
edea13f
Adjusted GOGC to make CircleCI happy
joe-elliott Sep 19, 2019
df2a539
Changed legacy => loghttp for consistency
joe-elliott Sep 19, 2019
e4e36fe
Fixed matrix error message to be correct
joe-elliott Sep 19, 2019
3c70563
Moved label query over to loghttp response
joe-elliott Sep 19, 2019
1ea9b96
Added marshal loop tests
joe-elliott Sep 20, 2019
f22281f
Added response type test
joe-elliott Sep 20, 2019
819874d
Fixed tail response marshal/unmarshal
joe-elliott Sep 20, 2019
1a7b475
Passing unmarshal/marshal queryresponse tests
joe-elliott Sep 20, 2019
0398d9e
Fixed vector and matrix
joe-elliott Sep 20, 2019
24e1ae3
Added output support for streams minus ordering
joe-elliott Sep 20, 2019
e555529
Fixed tailing
joe-elliott Sep 20, 2019
e47f605
Fixed output tests
joe-elliott Sep 20, 2019
1596d37
Fixed query tests
joe-elliott Sep 20, 2019
3346cec
Order log output
joe-elliott Sep 20, 2019
45413c8
Use labels instead of stream
joe-elliott Sep 20, 2019
51c558a
Lowered parallelization for CircleCI
joe-elliott Sep 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
- checkout
- run:
name: build
command: make GOOS=windows promtail
command: make GOOS=windows GOGC=10 promtail

# Docker driver
build/docker-driver:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ lint:
########

test: all
go test -p=6 ./...
GOGC=10 go test -p=4 ./...

#########
# Clean #
Expand Down
4 changes: 2 additions & 2 deletions pkg/canary/reader/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"

loghttp "github.com/grafana/loki/pkg/loghttp/legacy"
"github.com/grafana/loki/pkg/logproto"
"github.com/grafana/loki/pkg/querier"
)

var (
Expand Down Expand Up @@ -159,7 +159,7 @@ func (r *Reader) run() {

r.closeAndReconnect()

tailResponse := &querier.TailResponse{}
tailResponse := &loghttp.TailResponse{}

for {
err := r.conn.ReadJSON(tailResponse)
Expand Down
62 changes: 11 additions & 51 deletions pkg/logcli/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@ import (
"strings"
"time"

"github.com/prometheus/common/model"

"github.com/grafana/loki/pkg/logql"
"github.com/grafana/loki/pkg/loghttp"

"github.com/gorilla/websocket"
"github.com/prometheus/common/config"
"github.com/prometheus/prometheus/promql"

"github.com/grafana/loki/pkg/logproto"
)
Expand All @@ -38,16 +35,10 @@ type Client struct {
Address string
}

// QueryResult contains fields necessary to return data from Loki endpoints
type QueryResult struct {
ResultType promql.ValueType
Result interface{}
}

// Query uses the /api/v1/query endpoint to execute an instant query
// excluding interfacer b/c it suggests taking the interface promql.Node instead of logproto.Direction b/c it happens to have a String() method
// nolint:interfacer
func (c *Client) Query(queryStr string, limit int, time time.Time, direction logproto.Direction, quiet bool) (*QueryResult, error) {
func (c *Client) Query(queryStr string, limit int, time time.Time, direction logproto.Direction, quiet bool) (*loghttp.QueryResponse, error) {
path := fmt.Sprintf(queryPath,
url.QueryEscape(queryStr), // query
limit, // limit
Expand All @@ -61,7 +52,7 @@ func (c *Client) Query(queryStr string, limit int, time time.Time, direction log
// QueryRange uses the /api/v1/query_range endpoint to execute a range query
// excluding interfacer b/c it suggests taking the interface promql.Node instead of logproto.Direction b/c it happens to have a String() method
// nolint:interfacer
func (c *Client) QueryRange(queryStr string, limit int, from, through time.Time, direction logproto.Direction, quiet bool) (*QueryResult, error) {
func (c *Client) QueryRange(queryStr string, limit int, from, through time.Time, direction logproto.Direction, quiet bool) (*loghttp.QueryResponse, error) {
path := fmt.Sprintf(queryRangePath,
url.QueryEscape(queryStr), // query
limit, // limit
Expand All @@ -74,64 +65,33 @@ func (c *Client) QueryRange(queryStr string, limit int, from, through time.Time,
}

// ListLabelNames uses the /api/v1/label endpoint to list label names
func (c *Client) ListLabelNames(quiet bool) (*logproto.LabelResponse, error) {
var labelResponse logproto.LabelResponse
func (c *Client) ListLabelNames(quiet bool) (*loghttp.LabelResponse, error) {
var labelResponse loghttp.LabelResponse
if err := c.doRequest(labelsPath, quiet, &labelResponse); err != nil {
return nil, err
}
return &labelResponse, nil
}

// ListLabelValues uses the /api/v1/label endpoint to list label values
func (c *Client) ListLabelValues(name string, quiet bool) (*logproto.LabelResponse, error) {
func (c *Client) ListLabelValues(name string, quiet bool) (*loghttp.LabelResponse, error) {
path := fmt.Sprintf(labelValuesPath, url.PathEscape(name))
var labelResponse logproto.LabelResponse
var labelResponse loghttp.LabelResponse
if err := c.doRequest(path, quiet, &labelResponse); err != nil {
return nil, err
}
return &labelResponse, nil
}

func (c *Client) doQuery(path string, quiet bool) (*QueryResult, error) {
func (c *Client) doQuery(path string, quiet bool) (*loghttp.QueryResponse, error) {
var err error
var r loghttp.QueryResponse

unmarshal := struct {
Type promql.ValueType `json:"resultType"`
Result json.RawMessage `json:"result"`
}{}

if err = c.doRequest(path, quiet, &unmarshal); err != nil {
return nil, err
}

var value interface{}

// unmarshal results
switch unmarshal.Type {
case logql.ValueTypeStreams:
var s logql.Streams
err = json.Unmarshal(unmarshal.Result, &s)
value = s
case promql.ValueTypeMatrix:
var m model.Matrix
err = json.Unmarshal(unmarshal.Result, &m)
value = m
case promql.ValueTypeVector:
var m model.Vector
err = json.Unmarshal(unmarshal.Result, &m)
value = m
default:
return nil, fmt.Errorf("Unknown type: %s", unmarshal.Type)
}

if err != nil {
if err = c.doRequest(path, quiet, &r); err != nil {
return nil, err
}

return &QueryResult{
ResultType: unmarshal.Type,
Result: value,
}, nil
return &r, nil
}

func (c *Client) doRequest(path string, quiet bool, out interface{}) error {
Expand Down
4 changes: 2 additions & 2 deletions pkg/logcli/labelquery/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"log"

"github.com/grafana/loki/pkg/logcli/client"
"github.com/grafana/loki/pkg/logproto"
"github.com/grafana/loki/pkg/loghttp"
)

// LabelQuery contains all necessary fields to execute label queries and print out the resutls
Expand All @@ -25,7 +25,7 @@ func (q *LabelQuery) DoLabels(c *client.Client) {

// ListLabels returns an array of label strings
func (q *LabelQuery) ListLabels(c *client.Client) []string {
var labelResponse *logproto.LabelResponse
var labelResponse *loghttp.LabelResponse
var err error
if len(q.LabelName) > 0 {
labelResponse, err = c.ListLabelValues(q.LabelName, q.Quiet)
Expand Down
8 changes: 4 additions & 4 deletions pkg/logcli/output/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"time"

"github.com/fatih/color"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/grafana/loki/pkg/loghttp"
)

// DefaultOutput provides logs and metadata in human readable format
Expand All @@ -15,19 +15,19 @@ type DefaultOutput struct {
}

// Format a log entry in a human readable format
func (o *DefaultOutput) Format(ts time.Time, lbls *labels.Labels, maxLabelsLen int, line string) string {
func (o *DefaultOutput) Format(ts time.Time, lbls loghttp.LabelSet, maxLabelsLen int, line string) string {
timestamp := ts.In(o.options.Timezone).Format(time.RFC3339)
line = strings.TrimSpace(line)

if o.options.NoLabels {
return fmt.Sprintf("%s %s", color.BlueString(timestamp), line)
}

return fmt.Sprintf("%s %s %s", color.BlueString(timestamp), color.RedString(padLabel(*lbls, maxLabelsLen)), line)
return fmt.Sprintf("%s %s %s", color.BlueString(timestamp), color.RedString(padLabel(lbls, maxLabelsLen)), line)
}

// add some padding after labels
func padLabel(ls labels.Labels, maxLabelsLen int) string {
func padLabel(ls loghttp.LabelSet, maxLabelsLen int) string {
labels := ls.String()
if len(labels) < maxLabelsLen {
labels += strings.Repeat(" ", maxLabelsLen-len(labels))
Expand Down
41 changes: 25 additions & 16 deletions pkg/logcli/output/default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,69 +5,71 @@ import (
"testing"
"time"

"github.com/prometheus/prometheus/pkg/labels"
"github.com/grafana/loki/pkg/loghttp"
"github.com/stretchr/testify/assert"
)

func TestDefaultOutput_Format(t *testing.T) {
t.Parallel()

timestamp, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05+07:00")
emptyLabels := labels.New()
someLabels := labels.New(labels.Label{Name: "type", Value: "test"})
emptyLabels := loghttp.LabelSet{}
someLabels := loghttp.LabelSet(map[string]string{
"type": "test",
})

tests := map[string]struct {
options *LogOutputOptions
timestamp time.Time
lbls *labels.Labels
lbls loghttp.LabelSet
maxLabelsLen int
line string
expected string
}{
"empty line with no labels": {
&LogOutputOptions{Timezone: time.UTC, NoLabels: false},
timestamp,
&emptyLabels,
emptyLabels,
0,
"",
"2006-01-02T08:04:05Z {} ",
},
"empty line with labels": {
&LogOutputOptions{Timezone: time.UTC, NoLabels: false},
timestamp,
&someLabels,
someLabels,
len(someLabels.String()),
"",
"2006-01-02T08:04:05Z {type=\"test\"} ",
},
"max labels length shorter than input labels": {
&LogOutputOptions{Timezone: time.UTC, NoLabels: false},
timestamp,
&someLabels,
someLabels,
0,
"Hello",
"2006-01-02T08:04:05Z {type=\"test\"} Hello",
},
"max labels length longer than input labels": {
&LogOutputOptions{Timezone: time.UTC, NoLabels: false},
timestamp,
&someLabels,
someLabels,
20,
"Hello",
"2006-01-02T08:04:05Z {type=\"test\"} Hello",
},
"timezone option set to a Local one": {
&LogOutputOptions{Timezone: time.FixedZone("test", 2*60*60), NoLabels: false},
timestamp,
&someLabels,
someLabels,
0,
"Hello",
"2006-01-02T10:04:05+02:00 {type=\"test\"} Hello",
},
"labels output disabled": {
&LogOutputOptions{Timezone: time.UTC, NoLabels: true},
timestamp,
&someLabels,
someLabels,
0,
"Hello",
"2006-01-02T08:04:05Z Hello",
Expand All @@ -92,10 +94,17 @@ func TestDefaultOutput_FormatLabelsPadding(t *testing.T) {
t.Parallel()

// Define a list of labels that - once formatted - have a different length
labelsList := []labels.Labels{
labels.New(labels.Label{Name: "type", Value: "test"}),
labels.New(labels.Label{Name: "type", Value: "test"}, labels.Label{Name: "foo", Value: "bar"}),
labels.New(labels.Label{Name: "type", Value: "a-longer-test"}),
labelsList := []loghttp.LabelSet{
loghttp.LabelSet(map[string]string{
"type": "test",
}),
loghttp.LabelSet(map[string]string{
"type": "test",
"foo": "bar",
}),
loghttp.LabelSet(map[string]string{
"type": "a-longer-test",
}),
}

timestamp, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05+07:00")
Expand All @@ -106,7 +115,7 @@ func TestDefaultOutput_FormatLabelsPadding(t *testing.T) {
// Format the same log line with different labels
formattedEntries := make([]string, 0, len(labelsList))
for _, lbls := range labelsList {
formattedEntries = append(formattedEntries, out.Format(timestamp, &lbls, maxLabelsLen, "XXX"))
formattedEntries = append(formattedEntries, out.Format(timestamp, lbls, maxLabelsLen, "XXX"))
}

// Ensure the log line starts at the same position in each formatted output
Expand All @@ -122,7 +131,7 @@ func TestDefaultOutput_FormatLabelsPadding(t *testing.T) {
}
}

func findMaxLabelsLength(labelsList []labels.Labels) int {
func findMaxLabelsLength(labelsList []loghttp.LabelSet) int {
maxLabelsLen := 0

for _, lbls := range labelsList {
Expand Down
4 changes: 2 additions & 2 deletions pkg/logcli/output/jsonl.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"log"
"time"

"github.com/prometheus/prometheus/pkg/labels"
"github.com/grafana/loki/pkg/loghttp"
)

// JSONLOutput prints logs and metadata as JSON Lines, suitable for scripts
Expand All @@ -14,7 +14,7 @@ type JSONLOutput struct {
}

// Format a log entry as json line
func (o *JSONLOutput) Format(ts time.Time, lbls *labels.Labels, maxLabelsLen int, line string) string {
func (o *JSONLOutput) Format(ts time.Time, lbls loghttp.LabelSet, maxLabelsLen int, line string) string {
entry := map[string]interface{}{
"timestamp": ts.In(o.options.Timezone),
"line": line,
Expand Down
Loading