The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/public/app/features/logs/logsModel.test.ts

1954 lines
53 KiB

import { Observable } from 'rxjs';
import {
arrayToDataFrame,
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
createDataFrame,
DataFrame,
DataQuery,
DataQueryRequest,
DataQueryResponse,
DataTopic,
dateTimeParse,
FieldType,
getDefaultTimeRange,
LoadingState,
LogLevel,
LogRowModel,
LogsDedupStrategy,
LogsMetaKind,
LogsVolumeCustomMetaData,
LogsVolumeType,
sortDataFrame,
toDataFrame,
} from '@grafana/data';
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
import { config } from '@grafana/runtime';
import { LokiQueryDirection } from 'app/plugins/datasource/loki/dataquery.gen';
import { getMockFrames } from 'app/plugins/datasource/loki/mocks/frames';
import { MockObservableDataSourceApi } from '../../../test/mocks/datasource_srv';
import {
COMMON_LABELS,
dataFrameToLogsModel,
dedupLogRows,
getSeriesProperties,
LIMIT_LABEL,
TOTAL_LABEL,
logRowToSingleRowDataFrame,
logSeriesToLogsModel,
queryLogsSample,
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
queryLogsVolume,
} from './logsModel';
const FROM = dateTimeParse('2021-06-17 00:00:00', { timeZone: 'utc' });
const TO = dateTimeParse('2021-06-17 00:00:00', { timeZone: 'utc' });
describe('dedupLogRows()', () => {
test('should return rows as is when dedup is set to none', () => {
const rows = [
{
entry: 'WARN test 1.23 on [xxx]',
},
{
entry: 'WARN test 1.23 on [xxx]',
},
] as LogRowModel[];
expect(dedupLogRows(rows, LogsDedupStrategy.none)).toMatchObject(rows);
});
test('should dedup on exact matches', () => {
const rows = [
{
entry: 'WARN test 1.23 on [xxx]',
},
{
entry: 'WARN test 1.23 on [xxx]',
},
{
entry: 'INFO test 2.44 on [xxx]',
},
{
entry: 'WARN test 1.23 on [xxx]',
},
] as LogRowModel[];
expect(dedupLogRows(rows, LogsDedupStrategy.exact)).toEqual([
{
duplicates: 1,
entry: 'WARN test 1.23 on [xxx]',
},
{
duplicates: 0,
entry: 'INFO test 2.44 on [xxx]',
},
{
duplicates: 0,
entry: 'WARN test 1.23 on [xxx]',
},
]);
});
test('should dedup on number matches', () => {
const rows = [
{
entry: 'WARN test 1.2323423 on [xxx]',
},
{
entry: 'WARN test 1.23 on [xxx]',
},
{
entry: 'INFO test 2.44 on [xxx]',
},
{
entry: 'WARN test 1.23 on [xxx]',
},
] as LogRowModel[];
expect(dedupLogRows(rows, LogsDedupStrategy.numbers)).toEqual([
{
duplicates: 1,
entry: 'WARN test 1.2323423 on [xxx]',
},
{
duplicates: 0,
entry: 'INFO test 2.44 on [xxx]',
},
{
duplicates: 0,
entry: 'WARN test 1.23 on [xxx]',
},
]);
});
test('should dedup on signature matches', () => {
const rows = [
{
entry: 'WARN test 1.2323423 on [xxx]',
},
{
entry: 'WARN test 1.23 on [xxx]',
},
{
entry: 'INFO test 2.44 on [xxx]',
},
{
entry: 'WARN test 1.23 on [xxx]',
},
] as LogRowModel[];
expect(dedupLogRows(rows, LogsDedupStrategy.signature)).toEqual([
{
duplicates: 3,
entry: 'WARN test 1.2323423 on [xxx]',
},
]);
});
test('should return to non-deduped state on same log result', () => {
const rows = [
{
entry: 'INFO 123',
},
{
entry: 'WARN 123',
},
{
entry: 'WARN 123',
},
] as LogRowModel[];
expect(dedupLogRows(rows, LogsDedupStrategy.exact)).toEqual([
{
duplicates: 0,
entry: 'INFO 123',
},
{
duplicates: 1,
entry: 'WARN 123',
},
]);
expect(dedupLogRows(rows, LogsDedupStrategy.none)).toEqual(rows);
});
});
const emptyLogsModel = {
hasUniqueLabels: false,
rows: [],
meta: [],
series: [],
};
describe('dataFrameToLogsModel', () => {
it('given empty series should return empty logs model', () => {
expect(dataFrameToLogsModel([], 0)).toMatchObject(emptyLogsModel);
});
it('given series without correct series name should return empty logs model', () => {
const series: DataFrame[] = [
toDataFrame({
fields: [],
}),
];
expect(dataFrameToLogsModel(series, 0)).toMatchObject(emptyLogsModel);
});
it('given series without a time field should return empty logs model', () => {
const series: DataFrame[] = [
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
createDataFrame({
fields: [
{
name: 'message',
type: FieldType.string,
values: [],
},
],
}),
];
expect(dataFrameToLogsModel(series, 0)).toMatchObject(emptyLogsModel);
});
it('given series without a string field should return empty logs model', () => {
const series: DataFrame[] = [
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: [],
},
],
}),
];
expect(dataFrameToLogsModel(series, 0)).toMatchObject(emptyLogsModel);
});
it('given one series should return expected logs model', () => {
const series: DataFrame[] = [
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
},
{
name: 'message',
type: FieldType.string,
values: [
't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
],
labels: {
filename: '/var/log/grafana/grafana.log',
job: 'grafana',
},
},
{
name: 'id',
type: FieldType.string,
values: ['foo', 'bar'],
},
],
meta: {
limit: 1000,
},
refId: 'A',
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.hasUniqueLabels).toBeFalsy();
expect(logsModel.rows).toHaveLength(2);
expect(logsModel.rows).toMatchObject([
{
entry: 't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
logLevel: 'info',
uniqueLabels: {},
uid: 'A_foo',
},
{
entry: 't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
logLevel: 'error',
uniqueLabels: {},
uid: 'A_bar',
},
]);
expect(logsModel.series).toHaveLength(2);
expect(logsModel.series).toMatchObject([
{
name: 'info',
fields: [
{ type: 'time', values: [1556270891000, 1556289770000] },
{ type: 'number', values: [1, 0] },
],
},
{
name: 'error',
fields: [
{ type: 'time', values: [1556289770000] },
{ type: 'number', values: [1] },
],
},
]);
expect(logsModel.meta).toHaveLength(2);
expect(logsModel.meta![0]).toMatchObject({
label: '',
value: `2 lines returned`,
kind: LogsMetaKind.String,
});
expect(logsModel.meta![1]).toMatchObject({
label: COMMON_LABELS,
value: {
filename: '/var/log/grafana/grafana.log',
job: 'grafana',
},
kind: LogsMetaKind.LabelsMap,
});
});
it('given one series should return expected logs model with detected_level', () => {
const series: DataFrame[] = [
createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
},
{
name: 'message',
type: FieldType.string,
values: ['foo=bar', 'foo=bar'],
labels: {
job: 'grafana',
},
},
{
name: 'detected_level',
type: FieldType.string,
values: ['info', 'error'],
},
],
meta: {
limit: 1000,
},
refId: 'A',
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.hasUniqueLabels).toBeFalsy();
expect(logsModel.rows).toHaveLength(2);
expect(logsModel.rows).toMatchObject([
{
entry: 'foo=bar',
labels: { job: 'grafana' },
logLevel: 'info',
uniqueLabels: {},
uid: 'A_0',
},
{
entry: 'foo=bar',
labels: { job: 'grafana' },
logLevel: 'error',
uniqueLabels: {},
uid: 'A_1',
},
]);
expect(logsModel.series).toHaveLength(2);
expect(logsModel.series).toMatchObject([
{
name: 'info',
fields: [
{ type: 'time', values: [1556270891000, 1556289770000] },
{ type: 'number', values: [1, 0] },
],
},
{
name: 'error',
fields: [
{ type: 'time', values: [1556289770000] },
{ type: 'number', values: [1] },
],
},
]);
expect(logsModel.meta).toHaveLength(2);
expect(logsModel.meta![0]).toMatchObject({
label: '',
value: `2 lines returned`,
kind: LogsMetaKind.String,
});
expect(logsModel.meta![1]).toMatchObject({
label: COMMON_LABELS,
value: {
job: 'grafana',
},
kind: LogsMetaKind.LabelsMap,
});
});
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
it('with infinite scrolling enabled it should return expected logs model', () => {
config.featureToggles.logsInfiniteScrolling = true;
const series: DataFrame[] = [
createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: ['2019-04-26T09:28:11.352440161Z'],
},
{
name: 'message',
type: FieldType.string,
values: ['t=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server'],
labels: {},
},
{
name: 'id',
type: FieldType.string,
values: ['foo'],
},
],
meta: {
limit: 1000,
},
refId: 'A',
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.meta![0]).toMatchObject({
label: '',
value: `1 line displayed`,
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
kind: LogsMetaKind.String,
});
config.featureToggles.logsInfiniteScrolling = false;
});
it('given one series with limit as custom meta property should return correct limit', () => {
const series: DataFrame[] = getTestDataFrame();
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.meta![0]).toMatchObject({
label: '',
value: `2 lines returned`,
kind: LogsMetaKind.String,
});
});
it('given one series with total as custom meta property should return correct total', () => {
const series: DataFrame[] = [
createDataFrame({
fields: [],
meta: {
custom: {
total: 9999,
},
},
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.meta![0]).toMatchObject({
label: TOTAL_LABEL,
value: 9999,
kind: LogsMetaKind.Number,
});
});
it('given multiple series with total as custom meta property should return correct total', () => {
const series: DataFrame[] = [
createDataFrame({
fields: [],
meta: {
custom: {
total: 4,
},
},
}),
createDataFrame({
fields: [],
meta: {
custom: {
total: 5,
},
},
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.meta![0]).toMatchObject({
label: TOTAL_LABEL,
value: 9,
kind: LogsMetaKind.Number,
});
});
it('should return the expected meta when the line limit is reached', () => {
const series: DataFrame[] = getTestDataFrame();
series[0].meta = {
custom: {
limit: 2,
},
};
const timeRange = {
from: 1556270899999,
to: 1556357299999,
};
const queries = [
{
expr: 'test',
refId: 'A',
},
];
const logsModel = dataFrameToLogsModel(
series,
1,
{ from: timeRange.from.valueOf(), to: timeRange.to.valueOf() },
queries
);
expect(logsModel.meta).toEqual([
{
label: '',
value: '2 lines shown — 21.85% (5h 14min 40sec) of 24h',
kind: 1,
},
{
label: 'Common labels',
value: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
kind: 2,
},
]);
});
it('should skip the time coverage when the query direction is Scan', () => {
const series: DataFrame[] = getTestDataFrame();
series[0].meta = {
custom: {
limit: 2,
},
};
const timeRange = {
from: 1556270800000,
to: 1556270899999,
};
const queries = [
{
expr: 'test',
refId: 'A',
direction: LokiQueryDirection.Scan,
},
];
const logsModel = dataFrameToLogsModel(
series,
1,
{ from: timeRange.from.valueOf(), to: timeRange.to.valueOf() },
queries
);
expect(logsModel.meta).toEqual([
{
label: '',
value: '2 reached',
kind: 1,
},
{
label: 'Common labels',
value: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
kind: 2,
},
]);
});
it('given one series with labels-field should return expected logs model', () => {
const series: DataFrame[] = [
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
createDataFrame({
fields: [
{
name: 'labels',
type: FieldType.other,
values: [
{
filename: '/var/log/grafana/grafana.log',
job: 'grafana',
},
{
filename: '/var/log/grafana/grafana.log',
job: 'grafana',
},
],
},
{
name: 'time',
type: FieldType.time,
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
},
{
name: 'message',
type: FieldType.string,
values: [
't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
],
},
{
name: 'id',
type: FieldType.string,
values: ['foo', 'bar'],
},
],
meta: {
limit: 1000,
},
refId: 'A',
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.hasUniqueLabels).toBeFalsy();
expect(logsModel.rows).toHaveLength(2);
expect(logsModel.rows).toMatchObject([
{
entry: 't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
logLevel: 'info',
uniqueLabels: {},
uid: 'A_foo',
},
{
entry: 't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
logLevel: 'error',
uniqueLabels: {},
uid: 'A_bar',
},
]);
expect(logsModel.series).toHaveLength(2);
expect(logsModel.series).toMatchObject([
{
name: 'info',
fields: [
{ type: 'time', values: [1556270891000, 1556289770000] },
{ type: 'number', values: [1, 0] },
],
},
{
name: 'error',
fields: [
{ type: 'time', values: [1556289770000] },
{ type: 'number', values: [1] },
],
},
]);
expect(logsModel.meta).toHaveLength(2);
expect(logsModel.meta![0]).toMatchObject({
label: '',
value: `2 lines returned`,
kind: LogsMetaKind.String,
});
expect(logsModel.meta![1]).toMatchObject({
label: COMMON_LABELS,
value: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
kind: LogsMetaKind.LabelsMap,
});
});
it('given one series with labels-field it should work regardless the label-fields position', () => {
const labels = {
name: 'labels',
type: FieldType.other,
values: [
{
node: 'first',
mode: 'slow',
},
],
};
const time = {
name: 'time',
type: FieldType.time,
values: ['2019-04-26T09:28:11.352440161Z'],
};
const line = {
name: 'line',
type: FieldType.string,
values: ['line1'],
};
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
const frame1 = createDataFrame({
fields: [labels, time, line],
});
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
const frame2 = createDataFrame({
fields: [time, labels, line],
});
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
const frame3 = createDataFrame({
fields: [time, line, labels],
});
const logsModel1 = dataFrameToLogsModel([frame1], 1);
expect(logsModel1.rows).toHaveLength(1);
expect(logsModel1.rows[0].labels).toStrictEqual({ mode: 'slow', node: 'first' });
const logsModel2 = dataFrameToLogsModel([frame2], 1);
expect(logsModel2.rows).toHaveLength(1);
expect(logsModel2.rows[0].labels).toStrictEqual({ mode: 'slow', node: 'first' });
const logsModel3 = dataFrameToLogsModel([frame3], 1);
expect(logsModel3.rows).toHaveLength(1);
expect(logsModel3.rows[0].labels).toStrictEqual({ mode: 'slow', node: 'first' });
});
it('given one series with error should return expected logs model', () => {
const series: DataFrame[] = [
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
},
{
name: 'message',
type: FieldType.string,
values: [
't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
],
labels: {
filename: '/var/log/grafana/grafana.log',
job: 'grafana',
__error__: 'Failed while parsing',
},
},
{
name: 'id',
type: FieldType.string,
values: ['foo', 'bar'],
},
],
meta: {
limit: 1000,
custom: {
error: 'Error when parsing some of the logs',
},
},
refId: 'A',
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.hasUniqueLabels).toBeFalsy();
expect(logsModel.rows).toHaveLength(2);
expect(logsModel.rows).toMatchObject([
{
entry: 't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana', __error__: 'Failed while parsing' },
logLevel: 'info',
uniqueLabels: {},
uid: 'A_foo',
},
{
entry: 't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana', __error__: 'Failed while parsing' },
logLevel: 'error',
uniqueLabels: {},
uid: 'A_bar',
},
]);
expect(logsModel.series).toHaveLength(2);
expect(logsModel.meta).toHaveLength(3);
expect(logsModel.meta![0]).toMatchObject({
label: '',
value: `2 lines returned`,
kind: LogsMetaKind.String,
});
expect(logsModel.meta![1]).toMatchObject({
label: '',
value: 'Error when parsing some of the logs',
kind: LogsMetaKind.Error,
});
expect(logsModel.meta![2]).toMatchObject({
label: COMMON_LABELS,
value: series[0].fields[1].labels,
kind: LogsMetaKind.LabelsMap,
});
});
it('given one series without labels should return expected logs model', () => {
const series: DataFrame[] = [
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z'],
},
{
name: 'message',
type: FieldType.string,
values: ['WARN boooo'],
},
{
name: 'level',
type: FieldType.string,
values: ['dbug'],
},
],
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.rows).toHaveLength(1);
expect(logsModel.rows).toMatchObject([
{
entry: 'WARN boooo',
labels: {},
logLevel: LogLevel.debug,
uniqueLabels: {},
},
]);
});
it('given multiple series with duplicate results it should return unique uids', () => {
const series: DataFrame[] = [
toDataFrame({
refId: 'A',
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo'],
},
{
name: 'id',
type: FieldType.string,
values: ['duplicate_uid'],
},
],
}),
toDataFrame({
refId: 'B',
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo'],
},
{
name: 'id',
type: FieldType.string,
values: ['duplicate_uid'],
},
],
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
const uids = logsModel.rows.map((row) => row.uid);
expect(uids).toEqual(['A_duplicate_uid', 'B_duplicate_uid']);
});
it('given multiple series with unique times should return expected logs model', () => {
const series: DataFrame[] = [
toDataFrame({
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo'],
labels: {
foo: 'bar',
baz: '1',
level: 'dbug',
},
},
{
name: 'id',
type: FieldType.string,
values: ['0'],
},
],
}),
toDataFrame({
name: 'logs',
fields: [
{
name: 'time',
type: FieldType.time,
values: ['1970-01-01T00:00:00Z', '1970-01-01T00:00:02Z'],
},
{
name: 'message',
type: FieldType.string,
values: ['INFO 1', 'INFO 2'],
labels: {
foo: 'bar',
baz: '2',
level: 'err',
},
},
{
name: 'id',
type: FieldType.string,
values: ['1', '2'],
},
],
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.hasUniqueLabels).toBeTruthy();
expect(logsModel.rows).toHaveLength(3);
expect(logsModel.rows).toMatchObject([
{
entry: 'INFO 1',
labels: { foo: 'bar', baz: '2' },
logLevel: LogLevel.error,
uniqueLabels: { baz: '2' },
},
{
entry: 'WARN boooo',
labels: { foo: 'bar', baz: '1' },
logLevel: LogLevel.debug,
uniqueLabels: { baz: '1' },
},
{
entry: 'INFO 2',
labels: { foo: 'bar', baz: '2' },
logLevel: LogLevel.error,
uniqueLabels: { baz: '2' },
},
]);
expect(logsModel.series).toHaveLength(2);
expect(logsModel.series).toMatchObject([
{
name: 'error',
fields: [
{ type: 'time', values: [0, 1000, 2000] },
{ type: 'number', values: [1, 0, 1] },
],
},
{
name: 'debug',
fields: [
{ type: 'time', values: [1000, 2000] },
{ type: 'number', values: [1, 0] },
],
},
]);
expect(logsModel.meta).toHaveLength(1);
expect(logsModel.meta![0]).toMatchObject({
label: COMMON_LABELS,
value: {
foo: 'bar',
},
kind: LogsMetaKind.LabelsMap,
});
});
it('given multiple series with equal times should return expected logs model', () => {
const series: DataFrame[] = [
toDataFrame({
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:00Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo 1'],
labels: {
foo: 'bar',
baz: '1',
level: 'dbug',
},
},
{
name: 'id',
type: FieldType.string,
values: ['0'],
},
],
}),
toDataFrame({
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo 2'],
labels: {
foo: 'bar',
baz: '2',
level: 'dbug',
},
},
{
name: 'id',
type: FieldType.string,
values: ['1'],
},
],
}),
toDataFrame({
name: 'logs',
fields: [
{
name: 'time',
type: FieldType.time,
values: ['1970-01-01T00:00:00Z', '1970-01-01T00:00:01Z'],
},
{
name: 'message',
type: FieldType.string,
values: ['INFO 1', 'INFO 2'],
labels: {
foo: 'bar',
baz: '2',
level: 'err',
},
},
{
name: 'id',
type: FieldType.string,
values: ['2', '3'],
},
],
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.hasUniqueLabels).toBeTruthy();
expect(logsModel.rows).toHaveLength(4);
expect(logsModel.rows).toMatchObject([
{
entry: 'WARN boooo 1',
labels: { foo: 'bar', baz: '1' },
logLevel: LogLevel.debug,
uniqueLabels: { baz: '1' },
},
{
entry: 'INFO 1',
labels: { foo: 'bar', baz: '2' },
logLevel: LogLevel.error,
uniqueLabels: { baz: '2' },
},
{
entry: 'WARN boooo 2',
labels: { foo: 'bar', baz: '2' },
logLevel: LogLevel.debug,
uniqueLabels: { baz: '2' },
},
{
entry: 'INFO 2',
labels: { foo: 'bar', baz: '2' },
logLevel: LogLevel.error,
uniqueLabels: { baz: '2' },
},
]);
});
it('should return expected line limit meta info when returned number of series equal the log limit', () => {
const series: DataFrame[] = [
Logs: add infinite scrolling to Explore (#76348) * Explore: propose action, thunk, and decorators for load more * LogsContainer: add loadMore method * Query: remove unused var * Loading more: use navigation to simulate scrolling * Explore: figure out data combination * Fix imports * Explore: deduplicate results when using query splitting * LogsNavigation: add scroll behavior * Remove old code * Scroll: adjust delta value * Load more: remove refIds from signature We can resolve them inside Explore state * Load more: rename to loadMoreLogs * Infinite scrolling: use scrollElement to listen to scrolling events * Explore logs: add fixed height to scrollable logs container * Logs: make logs container the scrolling element * Logs: remove dynamic logs container size It works very well with 1 query, but breaks with more than 1 query or when Logs is not the last rendered panel * Logs navigation: revert changes * Infinite scroll: create component * Infinite scroll: refactor and clean up effect * Infinite scroll: support oldest first scrolling direction * Infinite scroll: support loading oldest logs in ascending and descending order * Infinite scroll: use scroll to top from logs navigation * Logs: make logs container smaller * Logs: make container smaller * State: integrate explore's loading states * Infinite scroll: add loading to effect dependency array * Infinite scroll: display message when scroll limit is reached * Infinite scroll: add support to scroll in both directions * Infinite scroll: capture wheel events for top scroll * scrollableLogsContainer: deprecate in favor of logsInfiniteScrolling * Infinite scroll: implement timerange limits * Infinite scroll: pass timezone * Fix unused variables and imports * Infinite scroll: implement timerange limits for absolute time * Infinite scroll: fix timerange limits for absolute and relative times * Infinite scroll: reset out-of-bounds message * Logs: make container taller * Line limit: use "displayed" instead of "returned" for infinite scrolling * Infinite scrolling: disable behavior when there is no scroll * Remove console log * Infinite scroll: hide limit reached message when using relative time * Logs: migrate styles to object notation * Prettier formatting * LogsModel: fix import order * Update betterer.results * Logs: remove exploreScrollableLogsContainer test * Infinite scroll: display loader * Infinite scroll: improve wheel handling * Explore: unify correlations code * Explore: move new function to helpers * Remove comment * Fix imports * Formatting * Query: add missing awaits in unit test * Logs model: add unit test * Combine frames: move code to feature/logs * Explore: move getCorrelations call back to query It was causing a weird test failure * Fix imports * Infinite scroll: parametrize scrolling threshold * Logs: fix overflow css * Infinite scroll: add basic unit test * Infinite scroll: add unit test for absolute time ranges * Formatting * Explore query: add custom interaction for scrolling * Query: move correlations before update time * Fix import in test * Update comment * Remove comment * Remove comment * Infinite scroll: report interactions from component * Fix import order * Rename action * Infinite scroll: update limit reached message * Explore logs: remove type assertion * Update betterer
2 years ago
createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
},
{
name: 'message',
type: FieldType.string,
values: [
't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
],
labels: {
filename: '/var/log/grafana/grafana.log',
job: 'grafana',
},
},
{
name: 'id',
type: FieldType.string,
values: ['foo', 'bar'],
},
],
meta: {
limit: 2,
},
}),
];
const logsModel = dataFrameToLogsModel(series, 1, { from: 1556270591353, to: 1556289770991 });
expect(logsModel.meta).toHaveLength(2);
expect(logsModel.meta![0]).toMatchObject({
label: '',
value: `2 lines shown — 98.44% (5h 14min 40sec) of 5h 19min 40sec`,
kind: LogsMetaKind.String,
});
expect(logsModel.meta![1]).toMatchObject({
label: COMMON_LABELS,
value: series[0].fields[1].labels,
kind: LogsMetaKind.LabelsMap,
});
});
it('should fallback to row index if no id', () => {
const series: DataFrame[] = [
toDataFrame({
refId: 'A',
labels: { foo: 'bar' },
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:00Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo 1'],
},
],
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.rows[0].uid).toBe('A_0');
});
describe('infinite scrolling', () => {
let frameA: DataFrame, frameB: DataFrame;
beforeEach(() => {
const { logFrameA, logFrameB } = getMockFrames();
logFrameA.refId = `A`;
logFrameA.fields[0].values = [1, 1];
logFrameA.fields[1].values = ['line', 'line'];
logFrameA.fields[3].values = ['3000000', '3000000'];
logFrameA.fields[4].values = ['id', 'id'];
logFrameB.refId = `B`;
logFrameB.fields[0].values = [2, 2];
logFrameB.fields[1].values = ['line 2', 'line 2'];
logFrameB.fields[3].values = ['4000000', '4000000'];
logFrameB.fields[4].values = ['id2', 'id2'];
frameA = logFrameA;
frameB = logFrameB;
});
it('deduplicates repeated log frames when called with deduplicate', () => {
const logsModel = dataFrameToLogsModel(
[frameA, frameB],
1,
{ from: 1556270591353, to: 1556289770991 },
[{ refId: `A` }, { refId: `B` }],
true
);
expect(logsModel.rows).toHaveLength(2);
expect(logsModel.rows[0].entry).toBe(frameA.fields[1].values[0]);
expect(logsModel.rows[1].entry).toBe(frameB.fields[1].values[0]);
});
it('does not remove repeated log frames when invoked without deduplicate', () => {
frameA.refId = 'A';
frameB.refId = 'B';
const logsModel = dataFrameToLogsModel([frameA, frameB], 1, { from: 1556270591353, to: 1556289770991 }, [
{ refId: 'A' },
{ refId: 'B' },
]);
expect(logsModel.rows).toHaveLength(4);
expect(logsModel.rows[0].entry).toBe(frameA.fields[1].values[0]);
expect(logsModel.rows[1].entry).toBe(frameA.fields[1].values[1]);
expect(logsModel.rows[2].entry).toBe(frameB.fields[1].values[0]);
expect(logsModel.rows[3].entry).toBe(frameB.fields[1].values[1]);
});
});
});
describe('logSeriesToLogsModel', () => {
it('should return correct metaData even if the data is empty', () => {
const logSeries: DataFrame[] = [
{
fields: [],
length: 0,
refId: 'A',
meta: {
searchWords: ['test'],
limit: 1000,
stats: [{ displayName: 'Summary: total bytes processed', value: 97048, unit: 'decbytes' }],
custom: { lokiQueryStatKey: 'Summary: total bytes processed' },
preferredVisualisationType: 'logs',
},
},
];
const metaData = {
hasUniqueLabels: false,
meta: [
{ label: LIMIT_LABEL, value: 1000, kind: 0 },
{ label: 'Total bytes processed', value: '97.0 kB', kind: 1 },
],
rows: [],
};
expect(logSeriesToLogsModel(logSeries)).toMatchObject(metaData);
});
it('should return correct metaData when some data frames have empty fields', () => {
const logSeries: DataFrame[] = [
toDataFrame({
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z', '1970-02-01T00:00:01Z', '1970-03-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo 0', 'WARN boooo 1', 'WARN boooo 2'],
labels: {
foo: 'bar',
level: 'dbug',
},
},
{
name: 'id',
type: FieldType.string,
values: ['0', '1', '2'],
},
],
refId: 'A',
meta: {
searchWords: ['test'],
limit: 1000,
stats: [{ displayName: 'Summary: total bytes processed', value: 97048, unit: 'decbytes' }],
custom: { lokiQueryStatKey: 'Summary: total bytes processed' },
preferredVisualisationType: 'logs',
},
}),
toDataFrame({
fields: [],
length: 0,
refId: 'B',
meta: {
searchWords: ['test'],
limit: 1000,
stats: [{ displayName: 'Summary: total bytes processed', value: 97048, unit: 'decbytes' }],
custom: { lokiQueryStatKey: 'Summary: total bytes processed' },
preferredVisualisationType: 'logs',
},
}),
];
const logsModel = dataFrameToLogsModel(logSeries, 0);
expect(logsModel.meta).toMatchObject([
{ kind: 0, label: LIMIT_LABEL, value: 2000 },
{ kind: 1, label: 'Total bytes processed', value: '194 kB' },
{ kind: 2, label: COMMON_LABELS, value: { foo: 'bar', level: 'dbug' } },
]);
expect(logsModel.rows).toHaveLength(3);
expect(logsModel.rows).toMatchObject([
{
entry: 'WARN boooo 0',
labels: { foo: 'bar' },
logLevel: LogLevel.debug,
},
{
entry: 'WARN boooo 1',
labels: { foo: 'bar' },
logLevel: LogLevel.debug,
},
{
entry: 'WARN boooo 2',
labels: { foo: 'bar' },
logLevel: LogLevel.debug,
},
]);
});
it('should return empty string if message field is undefined', () => {
const logSeries: DataFrame[] = [
toDataFrame({
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z', '1970-02-01T00:00:01Z', '1970-03-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo 0', undefined, 'WARN boooo 2'],
labels: {
foo: 'bar',
level: 'dbug',
},
},
{
name: 'id',
type: FieldType.string,
values: ['0', '1', '2'],
},
],
refId: 'A',
meta: {},
}),
];
const logsModel = dataFrameToLogsModel(logSeries, 0);
expect(logsModel.rows).toHaveLength(3);
expect(logsModel.rows).toMatchObject([
{
entry: 'WARN boooo 0',
labels: { foo: 'bar' },
logLevel: LogLevel.debug,
},
{
entry: '',
labels: { foo: 'bar' },
logLevel: LogLevel.debug,
},
{
entry: 'WARN boooo 2',
labels: { foo: 'bar' },
logLevel: LogLevel.debug,
},
]);
});
it('should correctly get the log level if the message has ANSI color', () => {
const logSeries: DataFrame[] = [
toDataFrame({
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['Line with ANSI \u001B[31mwarn\u001B[0m et dolor'],
},
{
name: 'id',
type: FieldType.string,
values: ['0'],
},
],
refId: 'A',
meta: {},
}),
];
const logsModel = dataFrameToLogsModel(logSeries, 0);
expect(logsModel.rows).toHaveLength(1);
expect(logsModel.rows[0].logLevel).toEqual(LogLevel.warn);
});
});
describe('getSeriesProperties()', () => {
it('sets a minimum bucket size', () => {
const result = getSeriesProperties([], 2, undefined, 3, 123);
expect(result.bucketSize).toBe(123);
});
it('does not adjust the bucketSize if there is no range', () => {
const result = getSeriesProperties([], 30, undefined, 70);
expect(result.bucketSize).toBe(2100);
});
it('does not adjust the bucketSize if the logs row times match the given range', () => {
const rows = [
{ entry: 'foo', timeEpochMs: 10 },
{ entry: 'bar', timeEpochMs: 20 },
] as LogRowModel[];
const range = { from: 10, to: 20 };
const result = getSeriesProperties(rows, 1, range, 2, 1);
expect(result.bucketSize).toBe(2);
expect(result.visibleRange).toMatchObject(range);
});
it('clamps the range and adjusts the bucketSize if the logs row times do not completely cover the given range', () => {
const rows = [
{ entry: 'foo', timeEpochMs: 10 },
{ entry: 'bar', timeEpochMs: 20 },
] as LogRowModel[];
const range = { from: 0, to: 30 };
const result = getSeriesProperties(rows, 3, range, 2, 1);
// Bucketsize 6 gets shortened to 4 because of new visible range is 20ms vs original range being 30ms
expect(result.bucketSize).toBe(4);
// From time is also aligned to bucketSize (divisible by 4)
expect(result.visibleRange).toMatchObject({ from: 8, to: 30 });
});
});
describe('logs volume', () => {
class TestDataQuery implements DataQuery {
refId = 'a';
target = '';
}
let volumeProvider: Observable<DataQueryResponse>,
datasource: MockObservableDataSourceApi,
request: DataQueryRequest<TestDataQuery>;
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
function createFrame(labels: object, timestamps: number[], values: number[], refId: string) {
return toDataFrame({
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
refId,
fields: [
{ name: 'Time', type: FieldType.time, values: timestamps },
{
name: 'Number',
type: FieldType.number,
values,
labels,
},
],
});
}
function setup(datasourceSetup: () => void) {
datasourceSetup();
request = {
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
targets: [
{ refId: 'A', target: 'volume query 1' },
{ refId: 'B', target: 'volume query 2' },
],
scopedVars: {},
Supplementary queries: allow plugin decoupling by allowing providers to return a request instance (#80281) * Supplementary queries: add support for providers returning a request instance * Formatting * DataSourceWithSupplementaryQueriesSupport: update getDataProvider signature * getLogLevelFromLabels: fix buggy implementation * getLogLevelFromKey: fix key type Why number?? * Revert "getLogLevelFromKey: fix key type" This reverts commit 14a95298a6f803cc3270e0421b2e04dd0d65f131. * getSupplementaryQueryProvider: remove observable support * Datasources: remove unnecessary check The switch is doing the same job * Supplementary queries: update unit test * datasource_srv: sync mock with real api * Formatting * Supplementary queries: pass targets from getSupplementaryQueryProvider * LogsVolumeQueryOptions: remove range and make extract level optional * logsModel: add missing range to test data * query: sync tests with changes * Formatting * DataSourceWithSupplementaryQueriesSupport: update interface with deprecated and new methods * DataSourceWithSupplementaryQueriesSupport: sync Loki and Elasticsearch * queryLogsVolume: extractLevel no longer customizable * Loki: update test * Supplementary queries: add support for the new method * hasSupplementaryQuerySupport: update signature * Formatting * Betterer * Query: update test * Supplementary queries: add test for the legacy API * Update public/app/features/explore/utils/supplementaryQueries.ts Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> --------- Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
1 year ago
requestId: '',
interval: '',
intervalMs: 0,
range: {
from: FROM,
to: TO,
Supplementary queries: allow plugin decoupling by allowing providers to return a request instance (#80281) * Supplementary queries: add support for providers returning a request instance * Formatting * DataSourceWithSupplementaryQueriesSupport: update getDataProvider signature * getLogLevelFromLabels: fix buggy implementation * getLogLevelFromKey: fix key type Why number?? * Revert "getLogLevelFromKey: fix key type" This reverts commit 14a95298a6f803cc3270e0421b2e04dd0d65f131. * getSupplementaryQueryProvider: remove observable support * Datasources: remove unnecessary check The switch is doing the same job * Supplementary queries: update unit test * datasource_srv: sync mock with real api * Formatting * Supplementary queries: pass targets from getSupplementaryQueryProvider * LogsVolumeQueryOptions: remove range and make extract level optional * logsModel: add missing range to test data * query: sync tests with changes * Formatting * DataSourceWithSupplementaryQueriesSupport: update interface with deprecated and new methods * DataSourceWithSupplementaryQueriesSupport: sync Loki and Elasticsearch * queryLogsVolume: extractLevel no longer customizable * Loki: update test * Supplementary queries: add support for the new method * hasSupplementaryQuerySupport: update signature * Formatting * Betterer * Query: update test * Supplementary queries: add test for the legacy API * Update public/app/features/explore/utils/supplementaryQueries.ts Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> --------- Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
1 year ago
raw: {
from: FROM,
to: TO,
},
},
Supplementary queries: allow plugin decoupling by allowing providers to return a request instance (#80281) * Supplementary queries: add support for providers returning a request instance * Formatting * DataSourceWithSupplementaryQueriesSupport: update getDataProvider signature * getLogLevelFromLabels: fix buggy implementation * getLogLevelFromKey: fix key type Why number?? * Revert "getLogLevelFromKey: fix key type" This reverts commit 14a95298a6f803cc3270e0421b2e04dd0d65f131. * getSupplementaryQueryProvider: remove observable support * Datasources: remove unnecessary check The switch is doing the same job * Supplementary queries: update unit test * datasource_srv: sync mock with real api * Formatting * Supplementary queries: pass targets from getSupplementaryQueryProvider * LogsVolumeQueryOptions: remove range and make extract level optional * logsModel: add missing range to test data * query: sync tests with changes * Formatting * DataSourceWithSupplementaryQueriesSupport: update interface with deprecated and new methods * DataSourceWithSupplementaryQueriesSupport: sync Loki and Elasticsearch * queryLogsVolume: extractLevel no longer customizable * Loki: update test * Supplementary queries: add support for the new method * hasSupplementaryQuerySupport: update signature * Formatting * Betterer * Query: update test * Supplementary queries: add test for the legacy API * Update public/app/features/explore/utils/supplementaryQueries.ts Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> --------- Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
1 year ago
timezone: '',
app: '',
startTime: 0,
};
volumeProvider = queryLogsVolume(datasource, request, {
targets: request.targets,
});
}
function setupMultipleResults() {
// level=unknown
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
const resultAFrame1 = createFrame({ app: 'app01' }, [100, 200, 300], [5, 5, 5], 'A');
// level=error
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
const resultAFrame2 = createFrame({ app: 'app01', level: 'error' }, [100, 200, 300], [0, 1, 0], 'B');
// level=unknown
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
const resultBFrame1 = createFrame({ app: 'app02' }, [100, 200, 300], [1, 2, 3], 'A');
// level=error
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
const resultBFrame2 = createFrame({ app: 'app02', level: 'error' }, [100, 200, 300], [1, 1, 1], 'B');
datasource = new MockObservableDataSourceApi('loki', [
{
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
state: LoadingState.Loading,
data: [resultAFrame1, resultAFrame2],
},
{
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
state: LoadingState.Done,
data: [resultBFrame1, resultBFrame2],
},
]);
}
function setupMultipleResultsStreaming() {
// level=unknown
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
const resultAFrame1 = createFrame({ app: 'app01' }, [100, 200, 300], [5, 5, 5], 'A');
// level=error
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
const resultAFrame2 = createFrame({ app: 'app01', level: 'error' }, [100, 200, 300], [0, 1, 0], 'B');
datasource = new MockObservableDataSourceApi('loki', [
{
state: LoadingState.Streaming,
data: [resultAFrame1],
},
{
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
state: LoadingState.Done,
data: [resultAFrame1, resultAFrame2],
},
]);
}
function setupLogsVolumeWithAnnotations() {
const resultAFrame1 = createFrame({ app: 'app01' }, [100, 200, 300], [5, 5, 5], 'A');
const loadingFrame = arrayToDataFrame([
{
time: 100,
timeEnd: 200,
isRegion: true,
color: 'rgba(120, 120, 120, 0.1)',
},
]);
loadingFrame.name = 'annotation';
loadingFrame.meta = {
dataTopic: DataTopic.Annotations,
};
datasource = new MockObservableDataSourceApi('loki', [
{
state: LoadingState.Streaming,
data: [resultAFrame1, loadingFrame],
},
{
state: LoadingState.Done,
data: [resultAFrame1],
},
]);
}
function setupErrorResponse() {
datasource = new MockObservableDataSourceApi('loki', [], undefined, 'Error message');
}
it('applies correct meta data', async () => {
setup(setupMultipleResults);
const logVolumeCustomMeta: LogsVolumeCustomMetaData = {
sourceQuery: { refId: 'A', target: 'volume query 1' } as DataQuery,
datasourceName: 'loki',
logsVolumeType: LogsVolumeType.FullRange,
absoluteRange: {
from: FROM.valueOf(),
to: TO.valueOf(),
},
};
await expect(volumeProvider).toEmitValuesWith((received) => {
expect(received).toContainEqual({ state: LoadingState.Loading, error: undefined, data: [] });
expect(received).toContainEqual({
state: LoadingState.Done,
error: undefined,
data: [
expect.objectContaining({
fields: expect.anything(),
meta: {
custom: logVolumeCustomMeta,
},
}),
expect.anything(),
],
});
});
});
Explore: Support mixed data sources for supplementary query (#63036) * Consolidate logs volume logic (full range and limited) * Fix showing limited histogram message * Test passing meta data to logs volume provider * Improve readability * Clean up types * Add basic support for multiple log volumes * Move the comment back to the right place * Improve readability * Clean up the logic to support Logs Samples * Update docs * Sort log volumes * Provide title to logs volume panel * Move logs volume cache to the provider factory * Add helper functions * Reuse only if queries are the same * Fix alphabetical sorting * Move caching out of the provider * Support errors and loading state * Remove unused code * Consolidate supplementary query utils * Add tests for supplementaryQueries * Update tests * Simplify logs volume extra info * Update tests * Remove comment * Update tests * Fix hiding the histogram for hidden queries * Simplify loading message * Update tests * Wait for full fallback histogram to load before showing it * Fix a typo * Add feedback comments * Move feedback comments to github * Do not filter out hidden queries as they may be used as references in other queries * Group log volume by refId * Support showing fallback histograms per query to avoid duplicates * Improve type-checking * Fix supplementaryQueries.test.ts * Fix logsModel.test.ts * Fix loading fallback results * Fix unit tests * WIP * Update deprecated styles * Simplify test * Simplify rendering zoom info * Update deprecated styles * Simplify getLogsVolumeDataSourceInfo * Simplify isLogsVolumeLimited() * Simplify rendering zoom info
2 years ago
it('applies correct meta data when streaming', async () => {
setup(setupMultipleResultsStreaming);
const logVolumeCustomMeta: LogsVolumeCustomMetaData = {
sourceQuery: { refId: 'A', target: 'volume query 1' } as DataQuery,
datasourceName: 'loki',
logsVolumeType: LogsVolumeType.FullRange,
absoluteRange: {
from: FROM.valueOf(),
to: TO.valueOf(),
},
};
await expect(volumeProvider).toEmitValuesWith((received) => {
expect(received).toContainEqual({ state: LoadingState.Loading, error: undefined, data: [] });
expect(received).toContainEqual({
state: LoadingState.Done,
error: undefined,
data: [
expect.objectContaining({
fields: expect.anything(),
meta: {
custom: logVolumeCustomMeta,
},
}),
expect.anything(),
],
});
});
});
it('returns error', async () => {
setup(setupErrorResponse);
await expect(volumeProvider).toEmitValuesWith((received) => {
expect(received).toMatchObject([
{ state: LoadingState.Loading, error: undefined, data: [] },
{
state: LoadingState.Error,
error: 'Error message',
data: [],
},
'Error message',
]);
});
});
it('handles annotations in responses', async () => {
setup(setupLogsVolumeWithAnnotations);
const logVolumeCustomMeta: LogsVolumeCustomMetaData = {
sourceQuery: { refId: 'A', target: 'volume query 1' } as DataQuery,
datasourceName: 'loki',
logsVolumeType: LogsVolumeType.FullRange,
absoluteRange: {
from: FROM.valueOf(),
to: TO.valueOf(),
},
};
await expect(volumeProvider).toEmitValuesWith((received) => {
expect(received).toContainEqual({ state: LoadingState.Loading, error: undefined, data: [] });
expect(received).toContainEqual({
state: LoadingState.Streaming,
error: undefined,
data: [
expect.objectContaining({
fields: expect.anything(),
meta: {
custom: logVolumeCustomMeta,
},
}),
expect.objectContaining({
fields: expect.anything(),
meta: {
dataTopic: DataTopic.Annotations,
},
name: 'annotation',
}),
],
});
expect(received).toContainEqual({
state: LoadingState.Done,
error: undefined,
data: [
expect.objectContaining({
fields: expect.anything(),
meta: {
custom: logVolumeCustomMeta,
},
}),
],
});
});
});
});
describe('logs sample', () => {
class TestDataQuery implements DataQuery {
refId = 'A';
target = '';
}
let logsSampleProvider: Observable<DataQueryResponse>,
datasource: MockObservableDataSourceApi,
request: DataQueryRequest<TestDataQuery>;
function createFrame(labels: object[], timestamps: number[], values: string[]) {
return toDataFrame({
fields: [
{ name: 'Time', type: FieldType.time, values: timestamps },
{
name: 'Line',
type: FieldType.string,
values,
},
{ name: 'labels', type: FieldType.other, values: labels },
],
});
}
function setup(datasourceSetup: () => void) {
datasourceSetup();
request = {
targets: [{ target: 'logs sample query 1' }, { target: 'logs sample query 2' }],
scopedVars: {},
} as unknown as DataQueryRequest<TestDataQuery>;
logsSampleProvider = queryLogsSample(datasource, request);
}
const resultAFrame1 = createFrame([{ app: 'app01' }], [100, 200, 300], ['line 1', 'line 2', 'line 3']);
const resultAFrame2 = createFrame(
[{ app: 'app01', level: 'error' }],
[400, 500, 600],
['line 4', 'line 5', 'line 6']
);
const resultBFrame1 = createFrame([{ app: 'app02' }], [700, 800, 900], ['line A', 'line B', 'line C']);
const resultBFrame2 = createFrame(
[{ app: 'app02', level: 'error' }],
[1000, 1100, 1200],
['line D', 'line E', 'line F']
);
function setupMultipleResults() {
datasource = new MockObservableDataSourceApi('loki', [
{
data: [resultAFrame1, resultAFrame2],
},
{
data: [resultBFrame1, resultBFrame2, resultAFrame1, resultAFrame2],
},
]);
}
function setupErrorResponse() {
datasource = new MockObservableDataSourceApi('loki', [], undefined, 'Error message');
}
it('returns data', async () => {
setup(setupMultipleResults);
await expect(logsSampleProvider).toEmitValuesWith((received) => {
expect(received).toContainEqual({ state: LoadingState.Loading, error: undefined, data: [] });
expect(received).toContainEqual(
expect.objectContaining({
data: expect.arrayContaining([
sortDataFrame(resultAFrame1, 0),
sortDataFrame(resultAFrame2, 0),
sortDataFrame(resultBFrame1, 0),
sortDataFrame(resultBFrame2, 0),
]),
})
);
});
});
it('returns error', async () => {
setup(setupErrorResponse);
await expect(logsSampleProvider).toEmitValuesWith((received) => {
expect(received).toMatchObject([
{ state: LoadingState.Loading, error: undefined, data: [] },
{
state: LoadingState.Error,
error: 'Error message',
data: [],
},
'Error message',
]);
});
});
});
describe('logs volume', () => {
class TestDataQuery implements DataQuery {
refId = 'A';
target = '';
}
let logsVolumeProvider: Observable<DataQueryResponse>,
datasource: MockObservableDataSourceApi,
request: DataQueryRequest<TestDataQuery>;
function createFrame() {
return toDataFrame({
fields: [
{
name: 'Time',
type: FieldType.time,
config: {},
values: [3000000, 4000000],
},
{
name: 'Value',
type: FieldType.number,
config: {},
values: [5, 4],
labels: {
level: 'debug',
},
},
],
});
}
function setup(datasourceSetup: () => void) {
datasourceSetup();
request = {
targets: [{ target: 'logs sample query 1' }, { target: 'logs sample query 2' }],
range: getDefaultTimeRange(),
scopedVars: {},
} as unknown as DataQueryRequest<TestDataQuery>;
logsVolumeProvider = queryLogsVolume(datasource, request, { targets: request.targets });
}
const dataFrame = createFrame();
function setupResult() {
datasource = new MockObservableDataSourceApi('loki', [
{
data: [dataFrame],
},
]);
}
function setupError() {
datasource = new MockObservableDataSourceApi('loki', [], undefined, 'Error message');
}
function setupErrorWithData() {
datasource = new MockObservableDataSourceApi(
'loki',
[
{
data: [dataFrame],
},
],
undefined,
'Error message'
);
}
it('returns logs volume data', async () => {
setup(setupResult);
await expect(logsVolumeProvider).toEmitValuesWith((received) => {
expect(received).toContainEqual({ state: LoadingState.Loading, error: undefined, data: [] });
expect(received).toContainEqual(
expect.objectContaining({
data: expect.arrayContaining([dataFrame]),
})
);
});
});
it('returns errors', async () => {
setup(setupError);
await expect(logsVolumeProvider).toEmitValuesWith((received) => {
expect(received).toMatchObject([
{ state: LoadingState.Loading, error: undefined, data: [] },
{
state: LoadingState.Error,
error: 'Error message',
data: [],
},
'Error message',
]);
});
});
it('returns errors and data', async () => {
setup(setupErrorWithData);
await expect(logsVolumeProvider).toEmitValuesWith((received) => {
expect(received).toMatchObject([
{ state: LoadingState.Loading, error: undefined, data: [] },
{
state: LoadingState.Error,
error: 'Error message',
data: [],
},
'Error message',
]);
});
});
});
const mockLogRow = {
dataFrame: toDataFrame({
fields: [
{ name: 'Time', type: FieldType.time, values: [0, 1] },
{
name: 'Line',
type: FieldType.string,
values: ['line1', 'line2'],
},
{ name: 'labels', type: FieldType.other, values: [{ app: 'app01' }, { app: 'app02' }] },
],
refId: 'Z',
}),
rowIndex: 0,
} as unknown as LogRowModel;
describe('logRowToDataFrame', () => {
it('should return a DataFrame with the values from the specified row', () => {
const result = logRowToSingleRowDataFrame(mockLogRow);
expect(result?.length).toBe(1);
expect(result?.fields[0].values[0]).toEqual(0);
expect(result?.fields[1].values[0]).toEqual('line1');
expect(result?.fields[2].values[0]).toEqual({ app: 'app01' });
});
it('should return a DataFrame with the values from the specified different row', () => {
const result = logRowToSingleRowDataFrame({ ...mockLogRow, rowIndex: 1 });
expect(result?.length).toBe(1);
expect(result?.fields[0].values[0]).toEqual(1);
expect(result?.fields[1].values[0]).toEqual('line2');
expect(result?.fields[2].values[0]).toEqual({ app: 'app02' });
});
it('should handle an empty DataFrame', () => {
const emptyLogRow = { dataFrame: { fields: [] }, rowIndex: 0 } as unknown as LogRowModel;
const result = logRowToSingleRowDataFrame(emptyLogRow);
expect(result?.length).toBe(0);
});
it('should handle rowIndex exceeding array bounds', () => {
const invalidRowIndex = 10;
const result = logRowToSingleRowDataFrame({ ...mockLogRow, rowIndex: invalidRowIndex });
expect(result).toBe(null);
});
it('should use refId from original DataFrame', () => {
const result = logRowToSingleRowDataFrame(mockLogRow);
expect(result?.refId).toBe(mockLogRow.dataFrame.refId);
});
});
function getTestDataFrame() {
return [
createDataFrame({
fields: [
{
name: 'time',
type: FieldType.time,
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
},
{
name: 'message',
type: FieldType.string,
values: [
't=2019-04-26T11:05:28+0200 lvl=info msg="Initializing DatasourceCacheService" logger=server',
't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
],
labels: {
filename: '/var/log/grafana/grafana.log',
job: 'grafana',
},
},
{
name: 'id',
type: FieldType.string,
values: ['foo', 'bar'],
},
],
meta: {
custom: {
limit: 1000,
},
},
}),
];
}