mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: add additional settings section (#71035)
* Loki: add additional settings section * Derived fields: add config subsection * Query settings: add config subsection * Loki config: use divider instead of hr * Derived fields: refactor legacy styles * Loki config: add divider between derived fields and query settings * Loki config: create alerting settings for Loki
This commit is contained in:
parent
f6f3d97288
commit
1b80df0168
@ -0,0 +1,23 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
import { createDefaultConfigOptions } from '../mocks';
|
||||
|
||||
import { AlertingSettings } from './AlertingSettings';
|
||||
|
||||
const options = createDefaultConfigOptions();
|
||||
|
||||
describe('AlertingSettings', () => {
|
||||
it('should render', () => {
|
||||
render(<AlertingSettings options={options} onOptionsChange={() => {}} />);
|
||||
expect(screen.getByText('Alerting')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should update alerting settings', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(<AlertingSettings options={options} onOptionsChange={onChange} />);
|
||||
await userEvent.click(screen.getByLabelText('Toggle switch'));
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
|
||||
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||
import { ConfigSubSection } from '@grafana/experimental';
|
||||
import { InlineField, InlineSwitch } from '@grafana/ui';
|
||||
|
||||
export function AlertingSettings({
|
||||
options,
|
||||
onOptionsChange,
|
||||
}: Pick<DataSourcePluginOptionsEditorProps, 'options' | 'onOptionsChange'>) {
|
||||
return (
|
||||
<ConfigSubSection title="Alerting">
|
||||
<InlineField
|
||||
labelWidth={29}
|
||||
label="Manage alert rules in Alerting UI"
|
||||
disabled={options.readOnly}
|
||||
tooltip="Manage alert rules for this data source. To manage other alerting resources, add an Alertmanager data source."
|
||||
>
|
||||
<InlineSwitch
|
||||
value={options.jsonData.manageAlerts !== false}
|
||||
onChange={(event) =>
|
||||
onOptionsChange({
|
||||
...options,
|
||||
jsonData: { ...options.jsonData, manageAlerts: event!.currentTarget.checked },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</InlineField>
|
||||
</ConfigSubSection>
|
||||
);
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { DataSourcePluginOptionsEditorProps, DataSourceSettings } from '@grafana/data';
|
||||
import { ConfigSection } from '@grafana/experimental';
|
||||
import { config, reportInteraction } from '@grafana/runtime';
|
||||
import { AlertingSettings, DataSourceHttpSettings } from '@grafana/ui';
|
||||
import { DataSourceHttpSettings } from '@grafana/ui';
|
||||
import { Divider } from 'app/core/components/Divider';
|
||||
|
||||
import { LokiOptions } from '../types';
|
||||
|
||||
import { AlertingSettings } from './AlertingSettings';
|
||||
import { DerivedFields } from './DerivedFields';
|
||||
import { QuerySettings } from './QuerySettings';
|
||||
|
||||
@ -40,6 +43,8 @@ export const ConfigEditor = (props: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Divider />
|
||||
|
||||
<DataSourceHttpSettings
|
||||
defaultUrl={'http://localhost:3100'}
|
||||
dataSourceConfig={options}
|
||||
@ -48,19 +53,28 @@ export const ConfigEditor = (props: Props) => {
|
||||
secureSocksDSProxyEnabled={config.secureSocksDSProxyEnabled}
|
||||
/>
|
||||
|
||||
<AlertingSettings<LokiOptions> options={options} onOptionsChange={onOptionsChange} />
|
||||
<Divider />
|
||||
|
||||
<QuerySettings
|
||||
maxLines={options.jsonData.maxLines || ''}
|
||||
onMaxLinedChange={(value) => onOptionsChange(setMaxLines(options, value))}
|
||||
predefinedOperations={options.jsonData.predefinedOperations || ''}
|
||||
onPredefinedOperationsChange={updatePredefinedOperations}
|
||||
/>
|
||||
|
||||
<DerivedFields
|
||||
fields={options.jsonData.derivedFields}
|
||||
onChange={(value) => onOptionsChange(setDerivedFields(options, value))}
|
||||
/>
|
||||
<ConfigSection
|
||||
title="Additional settings"
|
||||
description="Additional settings are optional settings that can be configured for more control over your data source."
|
||||
isCollapsible={true}
|
||||
isInitiallyOpen
|
||||
>
|
||||
<AlertingSettings options={options} onOptionsChange={onOptionsChange} />
|
||||
<Divider hideLine />
|
||||
<QuerySettings
|
||||
maxLines={options.jsonData.maxLines || ''}
|
||||
onMaxLinedChange={(value) => onOptionsChange(setMaxLines(options, value))}
|
||||
predefinedOperations={options.jsonData.predefinedOperations || ''}
|
||||
onPredefinedOperationsChange={updatePredefinedOperations}
|
||||
/>
|
||||
<Divider hideLine />
|
||||
<DerivedFields
|
||||
fields={options.jsonData.derivedFields}
|
||||
onChange={(value) => onOptionsChange(setDerivedFields(options, value))}
|
||||
/>
|
||||
</ConfigSection>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -2,7 +2,9 @@ import { css } from '@emotion/css';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2, VariableOrigin, DataLinkBuiltInVars } from '@grafana/data';
|
||||
import { ConfigSubSection } from '@grafana/experimental';
|
||||
import { Button, useTheme2 } from '@grafana/ui';
|
||||
import { ConfigDescriptionLink } from 'app/core/components/ConfigDescriptionLink';
|
||||
|
||||
import { DerivedFieldConfig } from '../types';
|
||||
|
||||
@ -10,13 +12,18 @@ import { DebugSection } from './DebugSection';
|
||||
import { DerivedField } from './DerivedField';
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
infoText: css`
|
||||
padding-bottom: ${theme.spacing(2)};
|
||||
color: ${theme.colors.text.secondary};
|
||||
addButton: css`
|
||||
margin-right: 10px;
|
||||
`,
|
||||
derivedField: css`
|
||||
margin-bottom: ${theme.spacing(1)};
|
||||
`,
|
||||
container: css`
|
||||
margin-bottom: ${theme.spacing(4)};
|
||||
`,
|
||||
debugSection: css`
|
||||
margin-top: ${theme.spacing(4)};
|
||||
`,
|
||||
});
|
||||
|
||||
type Props = {
|
||||
@ -38,14 +45,17 @@ export const DerivedFields = ({ fields = [], onChange }: Props) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">Derived fields</h3>
|
||||
|
||||
<div className={styles.infoText}>
|
||||
Derived fields can be used to extract new fields from a log message and create a link from its value.
|
||||
</div>
|
||||
|
||||
<div className="gf-form-group">
|
||||
<ConfigSubSection
|
||||
title="Derived fields"
|
||||
description={
|
||||
<ConfigDescriptionLink
|
||||
description="Derived fields can be used to extract new fields from a log message and create a link from its value."
|
||||
suffix="loki/#configure-derived-fields"
|
||||
feature="derived fields"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className={styles.container}>
|
||||
{fields.map((field, index) => {
|
||||
return (
|
||||
<DerivedField
|
||||
@ -77,9 +87,7 @@ export const DerivedFields = ({ fields = [], onChange }: Props) => {
|
||||
<div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className={css`
|
||||
margin-right: 10px;
|
||||
`}
|
||||
className={styles.addButton}
|
||||
icon="plus"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
@ -96,18 +104,18 @@ export const DerivedFields = ({ fields = [], onChange }: Props) => {
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showDebug && (
|
||||
<div className="gf-form-group">
|
||||
<DebugSection
|
||||
className={css`
|
||||
margin-bottom: 10px;
|
||||
`}
|
||||
derivedFields={fields}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
{showDebug && (
|
||||
<div className={styles.debugSection}>
|
||||
<DebugSection
|
||||
className={css`
|
||||
margin-bottom: 10px;
|
||||
`}
|
||||
derivedFields={fields}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ConfigSubSection>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
import { ConfigSubSection } from '@grafana/experimental';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Badge, LegacyForms } from '@grafana/ui';
|
||||
import { ConfigDescriptionLink } from 'app/core/components/ConfigDescriptionLink';
|
||||
|
||||
const { FormField } = LegacyForms;
|
||||
|
||||
@ -15,69 +17,75 @@ type Props = {
|
||||
export const QuerySettings = (props: Props) => {
|
||||
const { maxLines, onMaxLinedChange, predefinedOperations, onPredefinedOperationsChange } = props;
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">Queries</h3>
|
||||
<div className="gf-form-group">
|
||||
<ConfigSubSection
|
||||
title="Queries"
|
||||
description={
|
||||
<ConfigDescriptionLink
|
||||
description="Additional options to customize your querying experience. "
|
||||
suffix="loki/#configure-the-data-source"
|
||||
feature="query settings"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
label="Maximum lines"
|
||||
labelWidth={11}
|
||||
inputWidth={20}
|
||||
inputEl={
|
||||
<input
|
||||
type="number"
|
||||
className="gf-form-input width-8 gf-form-input--has-help-icon"
|
||||
value={maxLines}
|
||||
onChange={(event) => onMaxLinedChange(event.currentTarget.value)}
|
||||
spellCheck={false}
|
||||
placeholder="1000"
|
||||
/>
|
||||
}
|
||||
tooltip={
|
||||
<>
|
||||
Loki queries must contain a limit of the maximum number of lines returned (default: 1000). Increase this
|
||||
limit to have a bigger result set for ad-hoc analysis. Decrease this limit if your browser becomes
|
||||
sluggish when displaying the log results.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{config.featureToggles.lokiPredefinedOperations && (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
label="Maximum lines"
|
||||
label="Predefined operations"
|
||||
labelWidth={11}
|
||||
inputWidth={20}
|
||||
inputEl={
|
||||
<input
|
||||
type="number"
|
||||
className="gf-form-input width-8 gf-form-input--has-help-icon"
|
||||
value={maxLines}
|
||||
onChange={(event) => onMaxLinedChange(event.currentTarget.value)}
|
||||
type="string"
|
||||
className="gf-form-input width-20 gf-form-input--has-help-icon"
|
||||
value={predefinedOperations}
|
||||
onChange={(event) => onPredefinedOperationsChange(event.currentTarget.value)}
|
||||
spellCheck={false}
|
||||
placeholder="1000"
|
||||
placeholder="| unpack | line_format"
|
||||
/>
|
||||
}
|
||||
tooltip={
|
||||
<>
|
||||
Loki queries must contain a limit of the maximum number of lines returned (default: 1000). Increase
|
||||
this limit to have a bigger result set for ad-hoc analysis. Decrease this limit if your browser
|
||||
becomes sluggish when displaying the log results.
|
||||
</>
|
||||
<div>
|
||||
{
|
||||
'Predefined operations are used as an initial state for your queries. They are useful, if you want to unpack, parse or format all log lines. Currently we support only log operations starting with |. For example: | unpack | line_format "{{.message}}".'
|
||||
}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Badge
|
||||
text="Experimental"
|
||||
color="orange"
|
||||
icon="exclamation-triangle"
|
||||
tooltip="Predefined operations is an experimental feature that may change in the future."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{config.featureToggles.lokiPredefinedOperations && (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
label="Predefined operations"
|
||||
labelWidth={11}
|
||||
inputEl={
|
||||
<input
|
||||
type="string"
|
||||
className="gf-form-input width-20 gf-form-input--has-help-icon"
|
||||
value={predefinedOperations}
|
||||
onChange={(event) => onPredefinedOperationsChange(event.currentTarget.value)}
|
||||
spellCheck={false}
|
||||
placeholder="| unpack | line_format"
|
||||
/>
|
||||
}
|
||||
tooltip={
|
||||
<div>
|
||||
{
|
||||
'Predefined operations are used as an initial state for your queries. They are useful, if you want to unpack, parse or format all log lines. Currently we support only log operations starting with |. For example: | unpack | line_format "{{.message}}".'
|
||||
}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Badge
|
||||
text="Experimental"
|
||||
color="orange"
|
||||
icon="exclamation-triangle"
|
||||
tooltip="Predefined operations is an experimental feature that may change in the future."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</ConfigSubSection>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user