AzureMonitor: Traces updates (#68462)
* Use fully qualified resource identifiers * Add additional data link to explore parent span * Correctly order links to not break trace logs functionality
This commit is contained in:
@@ -36,16 +36,17 @@ type AzureLogAnalyticsDatasource struct {
|
||||
// AzureLogAnalyticsQuery is the query request that is built from the saved values for
|
||||
// from the UI
|
||||
type AzureLogAnalyticsQuery struct {
|
||||
RefID string
|
||||
ResultFormat string
|
||||
URL string
|
||||
TraceExploreQuery string
|
||||
TraceLogsExploreQuery string
|
||||
JSON json.RawMessage
|
||||
TimeRange backend.TimeRange
|
||||
Query string
|
||||
Resources []string
|
||||
QueryType string
|
||||
RefID string
|
||||
ResultFormat string
|
||||
URL string
|
||||
TraceExploreQuery string
|
||||
TraceParentExploreQuery string
|
||||
TraceLogsExploreQuery string
|
||||
JSON json.RawMessage
|
||||
TimeRange backend.TimeRange
|
||||
Query string
|
||||
Resources []string
|
||||
QueryType string
|
||||
}
|
||||
|
||||
func (e *AzureLogAnalyticsDatasource) ResourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client) {
|
||||
@@ -90,6 +91,7 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(ctx context.Context, logger l
|
||||
var queryString string
|
||||
var resultFormat string
|
||||
traceExploreQuery := ""
|
||||
traceParentExploreQuery := ""
|
||||
traceLogsExploreQuery := ""
|
||||
if query.QueryType == string(dataquery.AzureQueryTypeAzureLogAnalytics) {
|
||||
queryJSONModel := types.LogJSONQuery{}
|
||||
@@ -168,19 +170,26 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(ctx context.Context, logger l
|
||||
}
|
||||
sort.Strings(queryResources)
|
||||
|
||||
queryString = buildTracesQuery(operationId, queryJSONModel.AzureTraces.TraceTypes, queryJSONModel.AzureTraces.Filters, &resultFormat, queryResources)
|
||||
queryString = buildTracesQuery(operationId, nil, queryJSONModel.AzureTraces.TraceTypes, queryJSONModel.AzureTraces.Filters, &resultFormat, queryResources)
|
||||
traceIdVariable := "${__data.fields.traceID}"
|
||||
parentSpanIdVariable := "${__data.fields.parentSpanID}"
|
||||
if operationId == "" {
|
||||
traceExploreQuery = buildTracesQuery(traceIdVariable, queryJSONModel.AzureTraces.TraceTypes, queryJSONModel.AzureTraces.Filters, &resultFormat, queryResources)
|
||||
traceExploreQuery = buildTracesQuery(traceIdVariable, nil, queryJSONModel.AzureTraces.TraceTypes, queryJSONModel.AzureTraces.Filters, &resultFormat, queryResources)
|
||||
traceParentExploreQuery = buildTracesQuery(traceIdVariable, &parentSpanIdVariable, queryJSONModel.AzureTraces.TraceTypes, queryJSONModel.AzureTraces.Filters, &resultFormat, queryResources)
|
||||
traceLogsExploreQuery = buildTracesLogsQuery(traceIdVariable, queryResources)
|
||||
} else {
|
||||
traceExploreQuery = queryString
|
||||
traceParentExploreQuery = buildTracesQuery(operationId, &parentSpanIdVariable, queryJSONModel.AzureTraces.TraceTypes, queryJSONModel.AzureTraces.Filters, &resultFormat, queryResources)
|
||||
traceLogsExploreQuery = buildTracesLogsQuery(operationId, queryResources)
|
||||
}
|
||||
traceExploreQuery, err = macros.KqlInterpolate(logger, query, dsInfo, traceExploreQuery, "TimeGenerated")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create traces explore query: %s", err)
|
||||
}
|
||||
traceParentExploreQuery, err = macros.KqlInterpolate(logger, query, dsInfo, traceParentExploreQuery, "TimeGenerated")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create parent span traces explore query: %s", err)
|
||||
}
|
||||
traceLogsExploreQuery, err = macros.KqlInterpolate(logger, query, dsInfo, traceLogsExploreQuery, "TimeGenerated")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create traces logs explore query: %s", err)
|
||||
@@ -195,16 +204,17 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(ctx context.Context, logger l
|
||||
}
|
||||
|
||||
azureLogAnalyticsQueries = append(azureLogAnalyticsQueries, &AzureLogAnalyticsQuery{
|
||||
RefID: query.RefID,
|
||||
ResultFormat: resultFormat,
|
||||
URL: apiURL,
|
||||
JSON: query.JSON,
|
||||
TimeRange: query.TimeRange,
|
||||
Query: rawQuery,
|
||||
Resources: resources,
|
||||
QueryType: query.QueryType,
|
||||
TraceExploreQuery: traceExploreQuery,
|
||||
TraceLogsExploreQuery: traceLogsExploreQuery,
|
||||
RefID: query.RefID,
|
||||
ResultFormat: resultFormat,
|
||||
URL: apiURL,
|
||||
JSON: query.JSON,
|
||||
TimeRange: query.TimeRange,
|
||||
Query: rawQuery,
|
||||
Resources: resources,
|
||||
QueryType: query.QueryType,
|
||||
TraceExploreQuery: traceExploreQuery,
|
||||
TraceParentExploreQuery: traceParentExploreQuery,
|
||||
TraceLogsExploreQuery: traceLogsExploreQuery,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -333,8 +343,6 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, logger l
|
||||
dataResponse.Error = err
|
||||
return dataResponse
|
||||
}
|
||||
linkTitle := "Explore Trace in Azure Portal"
|
||||
AddConfigLinks(*frame, tracesUrl, &linkTitle)
|
||||
|
||||
queryJSONModel := dataquery.AzureMonitorQuery{}
|
||||
err = json.Unmarshal(query.JSON, &queryJSONModel)
|
||||
@@ -365,15 +373,32 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, logger l
|
||||
QueryType: &logsQueryType,
|
||||
}
|
||||
|
||||
AddCustomDataLink(*frame, data.DataLink{
|
||||
Title: "Explore Trace: ${__data.fields.traceID}",
|
||||
URL: "",
|
||||
Internal: &data.InternalDataLink{
|
||||
DatasourceUID: dsInfo.DatasourceUID,
|
||||
DatasourceName: dsInfo.DatasourceName,
|
||||
Query: queryJSONModel,
|
||||
},
|
||||
})
|
||||
if query.ResultFormat == string(dataquery.AzureMonitorQueryAzureTracesResultFormatTable) {
|
||||
AddCustomDataLink(*frame, data.DataLink{
|
||||
Title: "Explore Trace: ${__data.fields.traceID}",
|
||||
URL: "",
|
||||
Internal: &data.InternalDataLink{
|
||||
DatasourceUID: dsInfo.DatasourceUID,
|
||||
DatasourceName: dsInfo.DatasourceName,
|
||||
Query: queryJSONModel,
|
||||
},
|
||||
})
|
||||
|
||||
// Use the parent span query for the parent span data link
|
||||
queryJSONModel.AzureTraces.Query = &query.TraceParentExploreQuery
|
||||
AddCustomDataLink(*frame, data.DataLink{
|
||||
Title: "Explore Parent Span: ${__data.fields.parentSpanID}",
|
||||
URL: "",
|
||||
Internal: &data.InternalDataLink{
|
||||
DatasourceUID: dsInfo.DatasourceUID,
|
||||
DatasourceName: dsInfo.DatasourceName,
|
||||
Query: queryJSONModel,
|
||||
},
|
||||
})
|
||||
|
||||
linkTitle := "Explore Trace in Azure Portal"
|
||||
AddConfigLinks(*frame, tracesUrl, &linkTitle)
|
||||
}
|
||||
|
||||
AddCustomDataLink(*frame, data.DataLink{
|
||||
Title: "Explore Trace Logs",
|
||||
@@ -680,7 +705,7 @@ func encodeQuery(rawQuery string) (string, error) {
|
||||
return base64.StdEncoding.EncodeToString(b.Bytes()), nil
|
||||
}
|
||||
|
||||
func buildTracesQuery(operationId string, traceTypes []string, filters []types.TracesFilters, resultFormat *string, resources []string) string {
|
||||
func buildTracesQuery(operationId string, parentSpanID *string, traceTypes []string, filters []types.TracesFilters, resultFormat *string, resources []string) string {
|
||||
types := traceTypes
|
||||
if len(types) == 0 {
|
||||
types = Tables
|
||||
@@ -703,10 +728,8 @@ func buildTracesQuery(operationId string, traceTypes []string, filters []types.T
|
||||
if len(resources) > 0 {
|
||||
intermediate := make([]string, 0)
|
||||
for _, resource := range resources {
|
||||
resourceSplit := strings.SplitAfter(resource, "/")
|
||||
resourceName := resourceSplit[len(resourceSplit)-1]
|
||||
for _, table := range filteredTypes {
|
||||
intermediate = append(intermediate, fmt.Sprintf("app('%s').%s", resourceName, table))
|
||||
intermediate = append(intermediate, fmt.Sprintf("app('%s').%s", resource, table))
|
||||
}
|
||||
}
|
||||
resourcesQuery += "," + strings.Join(intermediate, ",")
|
||||
@@ -735,6 +758,11 @@ func buildTracesQuery(operationId string, traceTypes []string, filters []types.T
|
||||
whereClause = fmt.Sprintf("| where (operation_Id != '' and operation_Id == '%s') or (customDimensions.ai_legacyRootId != '' and customDimensions.ai_legacyRootId == '%s')", operationId, operationId)
|
||||
}
|
||||
|
||||
parentWhereClause := ""
|
||||
if parentSpanID != nil && *parentSpanID != "" {
|
||||
parentWhereClause = fmt.Sprintf("| where (operation_ParentId != '' and operation_ParentId == '%s')", *parentSpanID)
|
||||
}
|
||||
|
||||
filtersClause := ""
|
||||
|
||||
if len(filters) > 0 {
|
||||
@@ -771,7 +799,7 @@ func buildTracesQuery(operationId string, traceTypes []string, filters []types.T
|
||||
projectClause := `| project-rename traceID = operation_Id, parentSpanID = operation_ParentId, startTime = timestamp` +
|
||||
`| project startTime, itemType, serviceName, duration, traceID, spanID, parentSpanID, operationName, serviceTags, tags, itemId` +
|
||||
`| order by startTime asc`
|
||||
return baseQuery + whereClause + propertiesStaticQuery + errorProperty + propertiesQuery + filtersClause + projectClause
|
||||
return baseQuery + whereClause + parentWhereClause + propertiesStaticQuery + errorProperty + propertiesQuery + filtersClause + projectClause
|
||||
}
|
||||
|
||||
func buildTracesLogsQuery(operationId string, resources []string) string {
|
||||
@@ -781,10 +809,8 @@ func buildTracesLogsQuery(operationId string, resources []string) string {
|
||||
if len(resources) > 0 {
|
||||
intermediate := make([]string, 0)
|
||||
for _, resource := range resources {
|
||||
resourceSplit := strings.SplitAfter(resource, "/")
|
||||
resourceName := resourceSplit[len(resourceSplit)-1]
|
||||
for _, table := range types {
|
||||
intermediate = append(intermediate, fmt.Sprintf("app('%s').%s", resourceName, table))
|
||||
intermediate = append(intermediate, fmt.Sprintf("app('%s').%s", resource, table))
|
||||
}
|
||||
}
|
||||
sort.Strings(intermediate)
|
||||
|
||||
Reference in New Issue
Block a user