mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Tracing: Send tags, events, and references as raw json (#52245)
* Tracing: Send tags, events, and references as raw json * Update tempo fixture
This commit is contained in:
parent
c68ae0b616
commit
83c1756251
@ -1,5 +1,4 @@
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
const dataSourceName = 'PromExemplar';
|
||||
const addDataSource = () => {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -46,12 +46,12 @@ func TraceToFrame(td pdata.Traces) (*data.Frame, error) {
|
||||
data.NewField("parentSpanID", nil, []string{}),
|
||||
data.NewField("operationName", nil, []string{}),
|
||||
data.NewField("serviceName", nil, []string{}),
|
||||
data.NewField("serviceTags", nil, []string{}),
|
||||
data.NewField("serviceTags", nil, []json.RawMessage{}),
|
||||
data.NewField("startTime", nil, []float64{}),
|
||||
data.NewField("duration", nil, []float64{}),
|
||||
data.NewField("logs", nil, []string{}),
|
||||
data.NewField("references", nil, []string{}),
|
||||
data.NewField("tags", nil, []string{}),
|
||||
data.NewField("logs", nil, []json.RawMessage{}),
|
||||
data.NewField("references", nil, []json.RawMessage{}),
|
||||
data.NewField("tags", nil, []json.RawMessage{}),
|
||||
},
|
||||
Meta: &data.FrameMeta{
|
||||
// TODO: use constant once available in the SDK
|
||||
@ -147,23 +147,15 @@ func spanToSpanRow(span pdata.Span, libraryTags pdata.InstrumentationLibrary, re
|
||||
parentSpanID,
|
||||
span.Name(),
|
||||
serviceName,
|
||||
toJSONString(serviceTagsJson),
|
||||
json.RawMessage(serviceTagsJson),
|
||||
startTime,
|
||||
float64(span.EndTimestamp()-span.StartTimestamp()) / 1_000_000,
|
||||
toJSONString(logs),
|
||||
toJSONString(references),
|
||||
toJSONString(spanTags),
|
||||
json.RawMessage(logs),
|
||||
json.RawMessage(references),
|
||||
json.RawMessage(spanTags),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toJSONString(json []byte) string {
|
||||
s := string(json)
|
||||
if s == "null" {
|
||||
return ""
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func resourceToProcess(resource pdata.Resource) (string, []*KeyValue) {
|
||||
attrs := resource.Attributes()
|
||||
serviceName := tracetranslator.ResourceNoServiceName
|
||||
|
@ -1,6 +1,7 @@
|
||||
package tempo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
@ -34,21 +35,21 @@ func TestTraceToFrame(t *testing.T) {
|
||||
|
||||
require.Equal(t, "HTTP GET - loki_api_v1_query_range", root["operationName"])
|
||||
require.Equal(t, "loki-all", root["serviceName"])
|
||||
require.Equal(t, "[{\"value\":\"loki-all\",\"key\":\"service.name\"},{\"value\":\"Jaeger-Go-2.25.0\",\"key\":\"opencensus.exporterversion\"},{\"value\":\"4d019a031941\",\"key\":\"host.hostname\"},{\"value\":\"172.18.0.6\",\"key\":\"ip\"},{\"value\":\"4b19ace06df8e4de\",\"key\":\"client-uuid\"}]", root["serviceTags"])
|
||||
require.Equal(t, json.RawMessage("[{\"value\":\"loki-all\",\"key\":\"service.name\"},{\"value\":\"Jaeger-Go-2.25.0\",\"key\":\"opencensus.exporterversion\"},{\"value\":\"4d019a031941\",\"key\":\"host.hostname\"},{\"value\":\"172.18.0.6\",\"key\":\"ip\"},{\"value\":\"4b19ace06df8e4de\",\"key\":\"client-uuid\"}]"), root["serviceTags"])
|
||||
require.Equal(t, 1616072924070.497, root["startTime"])
|
||||
require.Equal(t, 8.421, root["duration"])
|
||||
require.Equal(t, "", root["logs"])
|
||||
require.Equal(t, "[{\"value\":\"const\",\"key\":\"sampler.type\"},{\"value\":true,\"key\":\"sampler.param\"},{\"value\":200,\"key\":\"http.status_code\"},{\"value\":\"GET\",\"key\":\"http.method\"},{\"value\":\"/loki/api/v1/query_range?direction=BACKWARD\\u0026limit=1000\\u0026query=%7Bcompose_project%3D%22devenv%22%7D%20%7C%3D%22traceID%22\\u0026start=1616070921000000000\\u0026end=1616072722000000000\\u0026step=2\",\"key\":\"http.url\"},{\"value\":\"net/http\",\"key\":\"component\"},{\"value\":\"server\",\"key\":\"span.kind\"},{\"value\":0,\"key\":\"status.code\"}]", root["tags"])
|
||||
require.Equal(t, json.RawMessage("null"), root["logs"])
|
||||
require.Equal(t, json.RawMessage("[{\"value\":\"const\",\"key\":\"sampler.type\"},{\"value\":true,\"key\":\"sampler.param\"},{\"value\":200,\"key\":\"http.status_code\"},{\"value\":\"GET\",\"key\":\"http.method\"},{\"value\":\"/loki/api/v1/query_range?direction=BACKWARD\\u0026limit=1000\\u0026query=%7Bcompose_project%3D%22devenv%22%7D%20%7C%3D%22traceID%22\\u0026start=1616070921000000000\\u0026end=1616072722000000000\\u0026step=2\",\"key\":\"http.url\"},{\"value\":\"net/http\",\"key\":\"component\"},{\"value\":\"server\",\"key\":\"span.kind\"},{\"value\":0,\"key\":\"status.code\"}]"), root["tags"])
|
||||
|
||||
span := bFrame.FindRowWithValue("spanID", "7198307df9748606")
|
||||
|
||||
require.Equal(t, "GetParallelChunks", span["operationName"])
|
||||
require.Equal(t, "loki-all", span["serviceName"])
|
||||
require.Equal(t, "[{\"value\":\"loki-all\",\"key\":\"service.name\"},{\"value\":\"Jaeger-Go-2.25.0\",\"key\":\"opencensus.exporterversion\"},{\"value\":\"4d019a031941\",\"key\":\"host.hostname\"},{\"value\":\"172.18.0.6\",\"key\":\"ip\"},{\"value\":\"4b19ace06df8e4de\",\"key\":\"client-uuid\"}]", span["serviceTags"])
|
||||
require.Equal(t, json.RawMessage("[{\"value\":\"loki-all\",\"key\":\"service.name\"},{\"value\":\"Jaeger-Go-2.25.0\",\"key\":\"opencensus.exporterversion\"},{\"value\":\"4d019a031941\",\"key\":\"host.hostname\"},{\"value\":\"172.18.0.6\",\"key\":\"ip\"},{\"value\":\"4b19ace06df8e4de\",\"key\":\"client-uuid\"}]"), span["serviceTags"])
|
||||
require.Equal(t, 1616072924072.852, span["startTime"])
|
||||
require.Equal(t, 0.094, span["duration"])
|
||||
require.Equal(t, "[{\"timestamp\":1616072924072.856,\"fields\":[{\"value\":1,\"key\":\"chunks requested\"}]},{\"timestamp\":1616072924072.9448,\"fields\":[{\"value\":1,\"key\":\"chunks fetched\"}]}]", span["logs"])
|
||||
require.Equal(t, "[{\"value\":0,\"key\":\"status.code\"}]", span["tags"])
|
||||
require.Equal(t, json.RawMessage("[{\"timestamp\":1616072924072.856,\"fields\":[{\"value\":1,\"key\":\"chunks requested\"}]},{\"timestamp\":1616072924072.9448,\"fields\":[{\"value\":1,\"key\":\"chunks fetched\"}]}]"), span["logs"])
|
||||
require.Equal(t, json.RawMessage("[{\"value\":0,\"key\":\"status.code\"}]"), span["tags"])
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -117,9 +117,9 @@ describe('Tempo data source', () => {
|
||||
{ name: 'operationName', values: ['store.validateQueryTimeRange'] },
|
||||
{ name: 'startTime', values: [1619712655875.4539] },
|
||||
{ name: 'duration', values: [14.984] },
|
||||
{ name: 'serviceTags', values: ['{"key":"servicetag1","value":"service"}'] },
|
||||
{ name: 'logs', values: ['{"timestamp":12345,"fields":[{"key":"count","value":1}]}'] },
|
||||
{ name: 'tags', values: ['{"key":"tag1","value":"val1"}'] },
|
||||
{ name: 'serviceTags', values: [{ key: 'servicetag1', value: 'service' }] },
|
||||
{ name: 'logs', values: [{ timestamp: 12345, fields: [{ key: 'count', value: 1 }] }] },
|
||||
{ name: 'tags', values: [{ key: 'tag1', value: 'val1' }] },
|
||||
{ name: 'serviceName', values: ['service'] },
|
||||
],
|
||||
})
|
||||
|
@ -1,20 +1,12 @@
|
||||
import { collectorTypes } from '@opentelemetry/exporter-collector';
|
||||
|
||||
import {
|
||||
ArrayVector,
|
||||
FieldType,
|
||||
MutableDataFrame,
|
||||
PluginType,
|
||||
DataSourceInstanceSettings,
|
||||
dateTime,
|
||||
} from '@grafana/data';
|
||||
import { FieldType, MutableDataFrame, PluginType, DataSourceInstanceSettings, dateTime } from '@grafana/data';
|
||||
|
||||
import {
|
||||
SearchResponse,
|
||||
createTableFrame,
|
||||
transformToOTLP,
|
||||
transformFromOTLP,
|
||||
transformTrace,
|
||||
createTableFrameFromSearch,
|
||||
} from './resultTransformer';
|
||||
import {
|
||||
@ -154,42 +146,3 @@ describe('transformFromOTLP()', () => {
|
||||
}).not.toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformTrace()', () => {
|
||||
// Mock the console error so that running the test suite doesnt throw the error
|
||||
const origError = console.error;
|
||||
const consoleErrorMock = jest.fn();
|
||||
afterEach(() => (console.error = origError));
|
||||
beforeEach(() => (console.error = consoleErrorMock));
|
||||
|
||||
const badFrame = new MutableDataFrame({
|
||||
fields: [
|
||||
{
|
||||
name: 'serviceTags',
|
||||
values: new ArrayVector([undefined]),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const goodFrame = new MutableDataFrame({
|
||||
fields: [
|
||||
{
|
||||
name: 'serviceTags',
|
||||
values: new ArrayVector(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
test('if passed bad data, will surface an error', () => {
|
||||
const response = transformTrace({ data: [badFrame] }, false);
|
||||
expect(response.data[0]).toBeFalsy();
|
||||
expect(response.error?.message).toBeTruthy();
|
||||
});
|
||||
|
||||
test('if passed good data, will parse successfully', () => {
|
||||
const response2 = transformTrace({ data: [goodFrame] }, false);
|
||||
expect(response2.data[0]).toBeTruthy();
|
||||
expect(response2.data[0]).toMatchObject(goodFrame);
|
||||
expect(response2.error).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
@ -5,11 +5,9 @@ import differenceInHours from 'date-fns/differenceInHours';
|
||||
import formatDistance from 'date-fns/formatDistance';
|
||||
|
||||
import {
|
||||
ArrayVector,
|
||||
DataFrame,
|
||||
DataQueryResponse,
|
||||
DataSourceInstanceSettings,
|
||||
Field,
|
||||
FieldType,
|
||||
MutableDataFrame,
|
||||
TraceKeyValuePair,
|
||||
@ -534,22 +532,12 @@ function getOTLPReferences(
|
||||
}
|
||||
|
||||
export function transformTrace(response: DataQueryResponse, nodeGraph = false): DataQueryResponse {
|
||||
// We need to parse some of the fields which contain stringified json.
|
||||
// Seems like we can't just map the values as the frame we got from backend has some default processing
|
||||
// and will stringify the json back when we try to set it. So we create a new field and swap it instead.
|
||||
const frame: DataFrame = response.data[0];
|
||||
|
||||
if (!frame) {
|
||||
return emptyDataQueryResponse;
|
||||
}
|
||||
|
||||
try {
|
||||
parseJsonFields(frame);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { error: { message: 'Unable to parse trace response: ' + error }, data: [] };
|
||||
}
|
||||
|
||||
let data = [...response.data];
|
||||
if (nodeGraph) {
|
||||
data.push(...createGraphFrames(frame));
|
||||
@ -561,30 +549,6 @@ export function transformTrace(response: DataQueryResponse, nodeGraph = false):
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Change fields which are json string into JS objects. Modifies the frame in place.
|
||||
*/
|
||||
function parseJsonFields(frame: DataFrame) {
|
||||
for (const fieldName of ['serviceTags', 'logs', 'tags', 'references']) {
|
||||
const field = frame.fields.find((f) => f.name === fieldName);
|
||||
if (field) {
|
||||
const fieldIndex = frame.fields.indexOf(field);
|
||||
const values = new ArrayVector();
|
||||
const newField: Field = {
|
||||
...field,
|
||||
values,
|
||||
type: FieldType.other,
|
||||
};
|
||||
|
||||
for (let i = 0; i < field.values.length; i++) {
|
||||
const value = field.values.get(i);
|
||||
values.set(i, value === '' ? undefined : JSON.parse(value));
|
||||
}
|
||||
frame.fields[fieldIndex] = newField;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type SearchResponse = {
|
||||
traceID: string;
|
||||
rootServiceName: string;
|
||||
|
Loading…
Reference in New Issue
Block a user