Create logs viewer
In this guide, you'll learn how to create simple visualizations to gather insights from your log data.
The LogStatusDistribution component
In the LogStatusDistribution
component, we'll visualize the log status distribution over time in a bar chart. We'll use DQL to fetch the logs data via the useDqlQuery
hook and the TimeseriesChart
component for the visualization, with a handy predefined log status color palette.
The DQL query is straightforward. Using the makeTimeseries
command, we can convert the raw log records to time series. We need to also convert the DQL result to the appropriate type for the TimeseriesChart
using the convertQueryResultToTimeseries
function. As we know, DQL doesn't guarantee any specific order in the results, so if we want a consistent and semantically valid visualization, we need to sort the time series data according to the status severity.
import React from 'react';
import { useDqlQuery } from '@dynatrace-sdk/react-hooks';
import { Flex } from '@dynatrace/strato-components/layouts';
import { ProgressCircle } from '@dynatrace/strato-components/content';
import { Heading } from '@dynatrace/strato-components/typography';
import {
convertQueryResultToTimeseries,
TimeseriesWithDimensions,
} from '@dynatrace/strato-components-preview/conversion-utilities';
import { TimeseriesChart } from '@dynatrace/strato-components-preview/charts';
import { Surface } from '@dynatrace/strato-components-preview/layouts-core';
import { QueryResult } from '@dynatrace-sdk/client-query';
const LOG_STATUS_QUERY = `fetch logs
| makeTimeseries count(), by:{status}, interval:5m`;
const getSeriesName = (series: TimeseriesWithDimensions) => {
return Array.isArray(series.name) ? series.name[0] : series.name;
};
const buildTimeseries = (result: QueryResult) => {
const timeseries = convertQueryResultToTimeseries(result);
const order = ['ERROR', 'WARN', 'INFO', 'NONE'];
timeseries.sort((a, b) => order.indexOf(getSeriesName(a)) - order.indexOf(getSeriesName(b)));
return timeseries;
};
export const LogStatusDistribution = () => {
const logSeries = useDqlQuery({ body: { query: LOG_STATUS_QUERY } });
return (
<Surface>
{logSeries.isLoading && <ProgressCircle />}
{logSeries.data && (
<Flex flexDirection="column" gap={24}>
<Heading level={3}>Log record distribution</Heading>
<TimeseriesChart colorPalette="log-status" data={buildTimeseries(logSeries.data)} variant="bar" />
</Flex>
)}
</Surface>
);
};
This operation requires the following scopes:
storage:buckets:read
storage:logs:read
The LogRecords component
The LogRecords
component consists of a table with the latest logs generated in our environment. Similarly to how we did in the LogStatusDistribution
component, we'll use DQL and the useDqlQuery
hook, but we'll use the DataTable
component for the visualization.
The DQL part is relatively simple. We use the fields
command to retrieve only the values that interest us, and then we sort
them by timestamp. The DataTable
component understands the DQL response format in this case, so no conversion is needed.
The DataTable
component is highly customizable. For our use case, we'll configure different colors for the log status using thresholds and color tokens for instant visual feedback, depending on the severity. We'll also add a toolbar with useful actions, the ability to sort the table, and pagination.
import React from 'react';
import { useDqlQuery } from '@dynatrace-sdk/react-hooks';
import { ProgressCircle } from '@dynatrace/strato-components/content';
import { Heading } from '@dynatrace/strato-components/typography';
import { DataTable, TableColumn } from '@dynatrace/strato-components-preview/tables';
import { Surface } from '@dynatrace/strato-components-preview/layouts-core';
import { Colors } from '@dynatrace/strato-design-tokens';
const LOG_RECORDS_QUERY = `fetch logs
| fields timestamp, status, content
| sort timestamp desc`;
const columns: TableColumn[] = [
{
header: 'Timestamp',
accessor: 'timestamp',
autoWidth: true,
columnType: 'date',
},
{
header: 'Status',
accessor: 'status',
autoWidth: true,
thresholds: [
{
value: 'INFO',
comparator: 'equal-to',
color: Colors.Charts.Logstatus.Info.Default,
},
{
value: 'WARN',
comparator: 'equal-to',
color: Colors.Charts.Logstatus.Warning.Default,
},
{
value: 'ERROR',
comparator: 'equal-to',
color: Colors.Charts.Logstatus.Error.Default,
},
],
},
{
header: 'Content',
accessor: 'content',
},
];
export const LogRecords = () => {
const logRecords = useDqlQuery({ body: { query: LOG_RECORDS_QUERY } });
return (
<Surface>
{logRecords.isLoading && <ProgressCircle />}
{logRecords.data && (
<>
<Heading level={3}>Most recent {logRecords.data.records.length} log records</Heading>
<DataTable
sortable
sortBy={{
id: 'timestamp',
desc: true,
}}
data={logRecords.data.records}
columns={columns}
lineWrap
>
<DataTable.Toolbar>
<DataTable.DownloadData />
<DataTable.LineWrap />
</DataTable.Toolbar>
<DataTable.Pagination defaultPageSize={20} />
</DataTable>
</>
)}
</Surface>
);
};
Putting it together
The last piece of the puzzle is using these components somewhere. We can simply instantiate them in the App
component, and we're done.
import React from 'react';
import { Heading } from '@dynatrace/strato-components/typography';
import { Flex } from '@dynatrace/strato-components/layouts';
import { Page } from '@dynatrace/strato-components-preview/layouts';
import { AppHeader } from '@dynatrace/strato-components-preview/layouts';
import { LogStatusDistribution } from './components/LogStatusDistribution';
import { LogRecords } from './components/LogRecords';
export const App = () => {
return (
<Page>
<Page.Header>
<AppHeader />
</Page.Header>
<Page.Main>
<Flex padding={16} flexDirection="column">
<Heading level={2}>Logs Viewer</Heading>
<LogStatusDistribution />
<LogRecords />
</Flex>
</Page.Main>
</Page>
);
};
Summary
Just like that, we've created a basic Logs Viewer app in no time. We hope you found this guide helpful and got the inspiration to build more Dynatrace Apps.