mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Updated cheat sheet with new filter syntax (#18947)
* Loki: Updated cheat sheet with new filter syntax - updated cheat sheet with new filter syntax - added user-specific examples from the user's label set - added link to LogQL docs - separated styles for examples (clickable) and expressions * Review feedback
This commit is contained in:
parent
c2bd36f550
commit
b392bba745
@ -299,6 +299,7 @@ export interface ExploreQueryFieldProps<
|
||||
}
|
||||
|
||||
export interface ExploreStartPageProps {
|
||||
datasource?: DataSourceApi;
|
||||
onClickExample: (query: DataQuery) => void;
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,11 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
return (
|
||||
<main className="m-t-2" style={{ width }}>
|
||||
<ErrorBoundaryAlert>
|
||||
{showingStartPage && <StartPage onClickExample={this.onClickExample} />}
|
||||
{showingStartPage && (
|
||||
<div className="grafana-info-box grafana-info-box--max-lg">
|
||||
<StartPage onClickExample={this.onClickExample} datasource={datasourceInstance} />
|
||||
</div>
|
||||
)}
|
||||
{!showingStartPage && (
|
||||
<>
|
||||
{mode === ExploreMode.Metrics && (
|
||||
|
@ -1,43 +1,101 @@
|
||||
import React from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { shuffle } from 'lodash';
|
||||
import { ExploreStartPageProps, DataQuery } from '@grafana/ui';
|
||||
import LokiLanguageProvider from '../language_provider';
|
||||
|
||||
const CHEAT_SHEET_ITEMS = [
|
||||
{
|
||||
title: 'See your logs',
|
||||
label: 'Start by selecting a log stream from the Log labels selector.',
|
||||
},
|
||||
{
|
||||
title: 'Logs from a "job"',
|
||||
expression: '{job="default/prometheus"}',
|
||||
label: 'Returns all log lines emitted by instances of this job.',
|
||||
},
|
||||
{
|
||||
title: 'Combine stream selectors',
|
||||
expression: '{app="cassandra",namespace="prod"}',
|
||||
label: 'Returns all log lines from streams that have both labels.',
|
||||
},
|
||||
{
|
||||
title: 'Search for text',
|
||||
expression: '{app="cassandra"} (duration|latency)\\s*(=|is|of)\\s*[\\d\\.]+',
|
||||
label: 'Add a regular expression after the selector to filter for.',
|
||||
},
|
||||
];
|
||||
const DEFAULT_EXAMPLES = ['{job="default/prometheus"}'];
|
||||
const PREFERRED_LABELS = ['job', 'app', 'k8s_app'];
|
||||
const EXAMPLES_LIMIT = 5;
|
||||
|
||||
export default (props: any) => (
|
||||
<div>
|
||||
<h2>Loki Cheat Sheet</h2>
|
||||
{CHEAT_SHEET_ITEMS.map(item => (
|
||||
<div className="cheat-sheet-item" key={item.title}>
|
||||
<div className="cheat-sheet-item__title">{item.title}</div>
|
||||
{item.expression && (
|
||||
<div
|
||||
className="cheat-sheet-item__expression"
|
||||
onClick={e => props.onClickExample({ refId: 'A', expr: item.expression })}
|
||||
>
|
||||
<code>{item.expression}</code>
|
||||
</div>
|
||||
)}
|
||||
<div className="cheat-sheet-item__label">{item.label}</div>
|
||||
export default class LokiCheatSheet extends PureComponent<ExploreStartPageProps, { userExamples: string[] }> {
|
||||
userLabelTimer: NodeJS.Timeout;
|
||||
state = {
|
||||
userExamples: DEFAULT_EXAMPLES,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.scheduleUserLabelChecking();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearTimeout(this.userLabelTimer);
|
||||
}
|
||||
|
||||
scheduleUserLabelChecking() {
|
||||
this.userLabelTimer = setTimeout(this.checkUserLabels, 1000);
|
||||
}
|
||||
|
||||
checkUserLabels = async () => {
|
||||
// Set example from user labels
|
||||
const provider: LokiLanguageProvider = this.props.datasource.languageProvider;
|
||||
if (provider.started) {
|
||||
const labels = provider.getLabelKeys() || [];
|
||||
const preferredLabel = PREFERRED_LABELS.find(l => labels.includes(l));
|
||||
if (preferredLabel) {
|
||||
const values = await provider.getLabelValues(preferredLabel);
|
||||
const userExamples = shuffle(values)
|
||||
.slice(0, EXAMPLES_LIMIT)
|
||||
.map(value => `{${preferredLabel}="${value}"}`);
|
||||
this.setState({ userExamples });
|
||||
}
|
||||
} else {
|
||||
this.scheduleUserLabelChecking();
|
||||
}
|
||||
};
|
||||
|
||||
renderExpression(expr: string) {
|
||||
const { onClickExample } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="cheat-sheet-item__example"
|
||||
key={expr}
|
||||
onClick={e => onClickExample({ refId: 'A', expr } as DataQuery)}
|
||||
>
|
||||
<code>{expr}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { userExamples } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Loki Cheat Sheet</h2>
|
||||
<div className="cheat-sheet-item">
|
||||
<div className="cheat-sheet-item__title">See your logs</div>
|
||||
<div className="cheat-sheet-item__label">Start by selecting a log stream from the Log labels selector.</div>
|
||||
<div className="cheat-sheet-item__label">
|
||||
Alternatively, you can write a stream selector into the query field:
|
||||
</div>
|
||||
{this.renderExpression('{job="default/prometheus"}')}
|
||||
{userExamples !== DEFAULT_EXAMPLES && userExamples.length > 0 ? (
|
||||
<div>
|
||||
<div className="cheat-sheet-item__label">Here are some example streams from your logs:</div>
|
||||
{userExamples.map(example => this.renderExpression(example))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="cheat-sheet-item">
|
||||
<div className="cheat-sheet-item__title">Combine stream selectors</div>
|
||||
{this.renderExpression('{app="cassandra",namespace="prod"}')}
|
||||
<div className="cheat-sheet-item__label">Returns all log lines from streams that have both labels.</div>
|
||||
</div>
|
||||
|
||||
<div className="cheat-sheet-item">
|
||||
<div className="cheat-sheet-item__title">Filtering for search terms.</div>
|
||||
{this.renderExpression('{app="cassandra"} |~ "(duration|latency)s*(=|is|of)s*[d.]+"')}
|
||||
{this.renderExpression('{app="cassandra"} |= "exact match"')}
|
||||
{this.renderExpression('{app="cassandra"} != "do not match"')}
|
||||
<div className="cheat-sheet-item__label">
|
||||
<a href="https://github.com/grafana/loki/blob/master/docs/usage.md#filter-expression" target="logql">
|
||||
LogQL
|
||||
</a>{' '}
|
||||
supports exact and regular expression filters.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import LokiCheatSheet from './LokiCheatSheet';
|
||||
import { ExploreStartPageProps } from '@grafana/ui';
|
||||
|
||||
export default class LokiStartPage extends PureComponent<ExploreStartPageProps> {
|
||||
render() {
|
||||
return (
|
||||
<div className="grafana-info-box grafana-info-box--max-lg">
|
||||
<LokiCheatSheet onClickExample={this.props.onClickExample} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -86,11 +86,23 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
*/
|
||||
start = () => {
|
||||
if (!this.startTask) {
|
||||
this.startTask = this.fetchLogLabels(this.initialRange);
|
||||
this.startTask = this.fetchLogLabels(this.initialRange).then(() => {
|
||||
this.started = true;
|
||||
return [];
|
||||
});
|
||||
}
|
||||
return this.startTask;
|
||||
};
|
||||
|
||||
getLabelKeys(): string[] {
|
||||
return this.labelKeys[EMPTY_SELECTOR];
|
||||
}
|
||||
|
||||
async getLabelValues(key: string): Promise<string[]> {
|
||||
await this.fetchLabelValues(key, this.initialRange);
|
||||
return this.labelValues[EMPTY_SELECTOR][key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return suggestions based on input that can be then plugged into a typeahead dropdown.
|
||||
* Keep this DOM-free for testing
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Datasource from './datasource';
|
||||
|
||||
import LokiStartPage from './components/LokiStartPage';
|
||||
import LokiCheatSheet from './components/LokiCheatSheet';
|
||||
import LokiQueryField from './components/LokiQueryField';
|
||||
import LokiQueryEditor from './components/LokiQueryEditor';
|
||||
import { LokiAnnotationsQueryCtrl } from './LokiAnnotationsQueryCtrl';
|
||||
@ -14,6 +14,6 @@ export {
|
||||
LokiQueryEditor as QueryEditor,
|
||||
LokiConfigCtrl as ConfigCtrl,
|
||||
LokiQueryField as ExploreQueryField,
|
||||
LokiStartPage as ExploreStartPage,
|
||||
LokiCheatSheet as ExploreStartPage,
|
||||
LokiAnnotationsQueryCtrl as AnnotationsQueryCtrl,
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { ExploreStartPageProps, DataQuery } from '@grafana/ui';
|
||||
|
||||
const CHEAT_SHEET_ITEMS = [
|
||||
{
|
||||
@ -19,15 +20,15 @@ const CHEAT_SHEET_ITEMS = [
|
||||
},
|
||||
];
|
||||
|
||||
export default (props: any) => (
|
||||
export default (props: ExploreStartPageProps) => (
|
||||
<div>
|
||||
<h2>PromQL Cheat Sheet</h2>
|
||||
{CHEAT_SHEET_ITEMS.map(item => (
|
||||
<div className="cheat-sheet-item" key={item.expression}>
|
||||
<div className="cheat-sheet-item__title">{item.title}</div>
|
||||
<div
|
||||
className="cheat-sheet-item__expression"
|
||||
onClick={e => props.onClickExample({ refId: 'A', expr: item.expression })}
|
||||
className="cheat-sheet-item__example"
|
||||
onClick={e => props.onClickExample({ refId: 'A', expr: item.expression } as DataQuery)}
|
||||
>
|
||||
<code>{item.expression}</code>
|
||||
</div>
|
||||
|
@ -1,13 +0,0 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import PromCheatSheet from './PromCheatSheet';
|
||||
import { ExploreStartPageProps } from '@grafana/ui';
|
||||
|
||||
export default class PromStart extends PureComponent<ExploreStartPageProps> {
|
||||
render() {
|
||||
return (
|
||||
<div className="grafana-info-box grafana-info-box--max-lg">
|
||||
<PromCheatSheet onClickExample={this.props.onClickExample} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ import { PrometheusDatasource } from './datasource';
|
||||
import { PromQueryEditor } from './components/PromQueryEditor';
|
||||
import { PrometheusConfigCtrl } from './config_ctrl';
|
||||
|
||||
import PrometheusStartPage from './components/PromStart';
|
||||
import PromCheatSheet from './components/PromCheatSheet';
|
||||
import PromQueryField from './components/PromQueryField';
|
||||
|
||||
class PrometheusAnnotationsQueryCtrl {
|
||||
@ -15,5 +15,5 @@ export {
|
||||
PrometheusConfigCtrl as ConfigCtrl,
|
||||
PrometheusAnnotationsQueryCtrl as AnnotationsQueryCtrl,
|
||||
PromQueryField as ExploreQueryField,
|
||||
PrometheusStartPage as ExploreStartPage,
|
||||
PromCheatSheet as ExploreStartPage,
|
||||
};
|
||||
|
@ -345,7 +345,7 @@
|
||||
font-size: $font-size-h3;
|
||||
}
|
||||
|
||||
.cheat-sheet-item__expression {
|
||||
.cheat-sheet-item__example {
|
||||
margin: $space-xs 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user