Merge branch 'develop' into feat/opamp-logparing

This commit is contained in:
Nityananda Gohain 2023-03-22 09:47:03 +05:30 committed by GitHub
commit 55d7285c9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 113 additions and 28 deletions

View File

@ -35,14 +35,31 @@ SigNoz helps developers monitor applications and troubleshoot problems in their
👉 Filter and query logs, build dashboards and alerts based on attributes in logs
![screenzy-1670570187181](https://user-images.githubusercontent.com/504541/206646629-829fdafe-70e2-4503-a9c4-1301b7918586.png)
<br />
![screenzy-1670570193901](https://user-images.githubusercontent.com/504541/206646676-a676fdeb-331c-4847-aea9-d1cabf7c47e1.png)
<br />
![screenzy-1670570199026](https://user-images.githubusercontent.com/504541/206646754-28c5534f-0377-428c-9c6e-5c7c0d9dd22d.png)
<br />
![screenzy-1670569888865](https://user-images.githubusercontent.com/504541/206645819-1e865a56-71b4-4fde-80cc-fbdb137a4da5.png)
👉 Record exceptions automatically in Python, Java, Ruby, and Javascript
👉 Easy to set alerts with DIY query builder
### Application Metrics
<img width="2560" alt="application_metrics" src="https://user-images.githubusercontent.com/83692067/226536399-be9298c9-b4c1-4879-83b9-bc73417c032c.png">
### Distributed Tracing
<img width="2068" alt="distributed_tracing_2 2" src="https://user-images.githubusercontent.com/83692067/226536447-bae58321-6a22-4ed3-af80-e3e964cb3489.png">
<img width="2068" alt="distributed_tracing_1" src="https://user-images.githubusercontent.com/83692067/226536462-939745b6-4f9d-45a6-8016-814837e7f7b4.png">
### Logs Management
<img width="2068" alt="logs_management" src="https://user-images.githubusercontent.com/83692067/226536482-b8a5c4af-b69c-43d5-969c-338bd5eaf1a5.png">
### Infrastructure Monitoring
<img width="2068" alt="infrastructure_monitoring" src="https://user-images.githubusercontent.com/83692067/226536496-f38c4dbf-e03c-4158-8be0-32d4a61158c7.png">
### Alerts
<img width="2068" alt="alerts_management" src="https://user-images.githubusercontent.com/83692067/226536548-2c81e2e8-c12d-47e8-bad7-c6be79055def.png">
<br /><br />
@ -65,6 +82,10 @@ Come say Hi to us on [Slack](https://signoz.io/slack) 👋
- See exact request trace to figure out issues in downstream services, slow DB queries, call to 3rd party services like payment gateways, etc
- Filter traces by service name, operation, latency, error, tags/annotations.
- Run aggregates on trace data (events/spans) to get business relevant metrics. e.g. You can get error rate and 99th percentile latency of `customer_type: gold` or `deployment_version: v2` or `external_call: paypal`
- Native support for OpenTelemetry Logs, advanced log query builder, and automatic log collection from k8s cluster
- Lightening quick log analytics ([Logs Perf. Benchmark](https://signoz.io/blog/logs-performance-benchmark/))
- End-to-End visibility into infrastructure performance, ingest metrics from all kinds of host environments
- Easy to set alerts with DIY query builder
<br /><br />

View File

@ -32,8 +32,9 @@ function TimePreference({
return (
<TextContainer noButtonMargin>
<Dropdown menu={menu} />
<Button>{selectedTime.name}</Button>
<Dropdown menu={menu}>
<Button>{selectedTime.name}</Button>
</Dropdown>
</TextContainer>
);
}

View File

@ -44,6 +44,9 @@ var AggregateOperatorToSQLFunc = map[model.AggregateOperator]string{
model.RATE_MIN: "min",
}
// See https://github.com/SigNoz/signoz/issues/2151#issuecomment-1467249056
var rateWithoutNegative = `if (runningDifference(value) < 0 OR runningDifference(ts) < 0, nan, runningDifference(value)/runningDifference(ts))`
var SupportedFunctions = []string{"exp", "log", "ln", "exp2", "log2", "exp10", "log10", "sqrt", "cbrt", "erf", "erfc", "lgamma", "tgamma", "sin", "cos", "tan", "asin", "acos", "atan", "degrees", "radians"}
func GoValuateFuncs() map[string]govaluate.ExpressionFunction {
@ -200,7 +203,7 @@ func BuildMetricQuery(qp *model.QueryRangeParamsV2, mq *model.MetricQuery, table
subQuery := fmt.Sprintf(
queryTmpl, "any(labels) as labels, "+groupTags, qp.Step, op, filterSubQuery, groupBy, groupTags,
) // labels will be same so any should be fine
query := `SELECT %s ts, runningDifference(value)/runningDifference(ts) as value FROM(%s)`
query := `SELECT %s ts, ` + rateWithoutNegative + ` as value FROM(%s)`
query = fmt.Sprintf(query, "labels as fullLabels,", subQuery)
return query, nil
@ -211,14 +214,14 @@ func BuildMetricQuery(qp *model.QueryRangeParamsV2, mq *model.MetricQuery, table
subQuery := fmt.Sprintf(
queryTmpl, rateGroupTags, qp.Step, op, filterSubQuery, rateGroupBy, rateGroupTags,
) // labels will be same so any should be fine
query := `SELECT %s ts, runningDifference(value)/runningDifference(ts) as value FROM(%s) OFFSET 1`
query := `SELECT %s ts, ` + rateWithoutNegative + `as value FROM(%s)`
query = fmt.Sprintf(query, groupTags, subQuery)
query = fmt.Sprintf(`SELECT %s ts, sum(value) as value FROM (%s) GROUP BY %s ORDER BY %s ts`, groupTags, query, groupBy, groupTags)
return query, nil
case model.RATE_SUM, model.RATE_MAX, model.RATE_AVG, model.RATE_MIN:
op := fmt.Sprintf("%s(value)", AggregateOperatorToSQLFunc[mq.AggregateOperator])
subQuery := fmt.Sprintf(queryTmpl, groupTags, qp.Step, op, filterSubQuery, groupBy, groupTags)
query := `SELECT %s ts, runningDifference(value)/runningDifference(ts) as value FROM(%s) OFFSET 1`
query := `SELECT %s ts, ` + rateWithoutNegative + `as value FROM(%s)`
query = fmt.Sprintf(query, groupTags, subQuery)
return query, nil
case model.P05, model.P10, model.P20, model.P25, model.P50, model.P75, model.P90, model.P95, model.P99:
@ -232,9 +235,10 @@ func BuildMetricQuery(qp *model.QueryRangeParamsV2, mq *model.MetricQuery, table
subQuery := fmt.Sprintf(
queryTmpl, rateGroupTags, qp.Step, op, filterSubQuery, rateGroupBy, rateGroupTags,
) // labels will be same so any should be fine
query := `SELECT %s ts, runningDifference(value)/runningDifference(ts) as value FROM(%s) OFFSET 1`
query := `SELECT %s ts, ` + rateWithoutNegative + ` as value FROM(%s)`
query = fmt.Sprintf(query, groupTags, subQuery)
query = fmt.Sprintf(`SELECT %s ts, sum(value) as value FROM (%s) GROUP BY %s ORDER BY %s ts`, groupTags, query, groupBy, groupTags)
// filter out NaN values from the rate query as histogramQuantile doesn't support NaN values
query = fmt.Sprintf(`SELECT %s ts, sum(value) as value FROM (%s) GROUP BY %s HAVING isNaN(value) = 0 ORDER BY %s ts`, groupTags, query, groupBy, groupTags)
value := AggregateOperatorToPercentile[mq.AggregateOperator]
query = fmt.Sprintf(`SELECT %s ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), %.3f) as value FROM (%s) GROUP BY %s ORDER BY %s ts`, groupTagsWithoutLe, value, query, groupByWithoutLe, groupTagsWithoutLe)

View File

@ -28,7 +28,30 @@ func TestBuildQuery(t *testing.T) {
queries := PrepareBuilderMetricQueries(q, "table").Queries
So(len(queries), ShouldEqual, 1)
So(queries["A"], ShouldContainSubstring, "WHERE metric_name = 'name'")
So(queries["A"], ShouldContainSubstring, "runningDifference(value)/runningDifference(ts)")
So(queries["A"], ShouldContainSubstring, rateWithoutNegative)
})
Convey("TestSimpleQueryWithHistQuantile", t, func() {
q := &model.QueryRangeParamsV2{
Start: 1650991982000,
End: 1651078382000,
Step: 60,
CompositeMetricQuery: &model.CompositeMetricQuery{
BuilderQueries: map[string]*model.MetricQuery{
"A": {
QueryName: "A",
MetricName: "name",
AggregateOperator: model.HIST_QUANTILE_99,
Expression: "A",
},
},
},
}
queries := PrepareBuilderMetricQueries(q, "table").Queries
So(len(queries), ShouldEqual, 1)
So(queries["A"], ShouldContainSubstring, "WHERE metric_name = 'name'")
So(queries["A"], ShouldContainSubstring, rateWithoutNegative)
So(queries["A"], ShouldContainSubstring, "HAVING isNaN(value) = 0")
})
}
@ -57,7 +80,7 @@ func TestBuildQueryWithFilters(t *testing.T) {
So(len(queries), ShouldEqual, 1)
So(queries["A"], ShouldContainSubstring, "WHERE metric_name = 'name' AND JSONExtractString(labels, 'a') != 'b'")
So(queries["A"], ShouldContainSubstring, "runningDifference(value)/runningDifference(ts)")
So(queries["A"], ShouldContainSubstring, rateWithoutNegative)
So(queries["A"], ShouldContainSubstring, "not match(JSONExtractString(labels, 'code'), 'ERROR_*')")
})
}
@ -91,7 +114,7 @@ func TestBuildQueryWithMultipleQueries(t *testing.T) {
queries := PrepareBuilderMetricQueries(q, "table").Queries
So(len(queries), ShouldEqual, 2)
So(queries["A"], ShouldContainSubstring, "WHERE metric_name = 'name' AND JSONExtractString(labels, 'in') IN ['a','b','c']")
So(queries["A"], ShouldContainSubstring, "runningDifference(value)/runningDifference(ts)")
So(queries["A"], ShouldContainSubstring, rateWithoutNegative)
})
}
@ -128,7 +151,7 @@ func TestBuildQueryWithMultipleQueriesAndFormula(t *testing.T) {
So(len(queries), ShouldEqual, 3)
So(queries["C"], ShouldContainSubstring, "SELECT A.ts as ts, A.value / B.value")
So(queries["C"], ShouldContainSubstring, "WHERE metric_name = 'name' AND JSONExtractString(labels, 'in') IN ['a','b','c']")
So(queries["C"], ShouldContainSubstring, "runningDifference(value)/runningDifference(ts)")
So(queries["C"], ShouldContainSubstring, rateWithoutNegative)
})
}

View File

@ -229,7 +229,6 @@ type FilterAttributeKeyResponse struct {
type AttributeKeyType string
const (
AttributeKeyTypeColumn AttributeKeyType = "column"
AttributeKeyTypeTag AttributeKeyType = "tag"
AttributeKeyTypeResource AttributeKeyType = "resource"
)
@ -238,6 +237,29 @@ type AttributeKey struct {
Key string `json:"key"`
DataType AttributeKeyDataType `json:"dataType"`
Type AttributeKeyType `json:"type"`
IsColumn bool `json:"isColumn"`
}
func (a AttributeKey) Validate() error {
switch a.DataType {
case AttributeKeyDataTypeBool, AttributeKeyDataTypeNumber, AttributeKeyDataTypeString:
break
default:
return fmt.Errorf("invalid attribute dataType: %s", a.DataType)
}
switch a.Type {
case AttributeKeyTypeResource, AttributeKeyTypeTag:
break
default:
return fmt.Errorf("invalid attribute type: %s", a.Type)
}
if a.Key == "" {
return fmt.Errorf("key is empty")
}
return nil
}
type FilterAttributeValueResponse struct {
@ -345,9 +367,9 @@ type BuilderQuery struct {
QueryName string `json:"queryName"`
DataSource DataSource `json:"dataSource"`
AggregateOperator AggregateOperator `json:"aggregateOperator"`
AggregateAttribute string `json:"aggregateAttribute,omitempty"`
AggregateAttribute AttributeKey `json:"aggregateAttribute,omitempty"`
Filters *FilterSet `json:"filters,omitempty"`
GroupBy []string `json:"groupBy,omitempty"`
GroupBy []AttributeKey `json:"groupBy,omitempty"`
Expression string `json:"expression"`
Disabled bool `json:"disabled"`
Having []Having `json:"having,omitempty"`
@ -356,7 +378,7 @@ type BuilderQuery struct {
PageSize uint64 `json:"pageSize"`
OrderBy []OrderBy `json:"orderBy,omitempty"`
ReduceTo ReduceToOperator `json:"reduceTo,omitempty"`
SelectColumns []string `json:"selectColumns,omitempty"`
SelectColumns []AttributeKey `json:"selectColumns,omitempty"`
}
func (b *BuilderQuery) Validate() error {
@ -376,7 +398,7 @@ func (b *BuilderQuery) Validate() error {
if err := b.AggregateOperator.Validate(); err != nil {
return fmt.Errorf("aggregate operator is invalid: %w", err)
}
if b.AggregateAttribute == "" && b.AggregateOperator.RequireAttribute() {
if b.AggregateAttribute == (AttributeKey{}) && b.AggregateOperator.RequireAttribute() {
return fmt.Errorf("aggregate attribute is required")
}
}
@ -388,11 +410,20 @@ func (b *BuilderQuery) Validate() error {
}
if b.GroupBy != nil {
for _, groupBy := range b.GroupBy {
if groupBy == "" {
return fmt.Errorf("group by cannot be empty")
if groupBy.Validate() != nil {
return fmt.Errorf("group by is invalid")
}
}
}
if b.SelectColumns != nil {
for _, selectColumn := range b.SelectColumns {
if selectColumn.Validate() != nil {
return fmt.Errorf("select column is invalid")
}
}
}
if b.Expression == "" {
return fmt.Errorf("expression is required")
}
@ -411,13 +442,18 @@ func (f *FilterSet) Validate() error {
if f.Operator != "" && f.Operator != "AND" && f.Operator != "OR" {
return fmt.Errorf("operator must be AND or OR")
}
for _, item := range f.Items {
if err := item.Key.Validate(); err != nil {
return fmt.Errorf("filter item key is invalid: %w", err)
}
}
return nil
}
type FilterItem struct {
Key string `json:"key"`
Value interface{} `json:"value"`
Operator string `json:"op"`
Key AttributeKey `json:"key"`
Value interface{} `json:"value"`
Operator string `json:"op"`
}
type OrderBy struct {