Skip to content

Commit

Permalink
Merge remote-tracking branch 'grafana/master' into stats-filter
Browse files Browse the repository at this point in the history
* grafana/master:
  Fix: Bring back styles on Switch components when checked
  Update CHANGELOG.md
  Chore: breaks build if certain FrontEnd limits are exceeded (grafana#16301)
  Fix: Graphite query ast to string fix (grafana#16297)
  Fix: Template query editor this bind exception fix (grafana#16299)
  Fix: Alerting Notification channel http api fixes (grafana#16288)
  Refactor: Move LogLevel and Labels utils to @grafana/ui (grafana#16285)
  Refactor: Rename Tags to Labels in SeriesData (simple) (grafana#16284)
  Elasticsearch: Fix view percentiles metric in table without date histogram (grafana#15686)
  Configuration: Improve session_lifetime comments (grafana#16238)
  Alerting: Makes timeouts and retries configurable (grafana#16259)
  Fix: Correct SnapshotData typing (grafana#16279)
  Feat: Angular panels & SeriesData to Table/TimeSeries (grafana#16266)
  Fix: React Graph & Show message on no data (grafana#16278)
  • Loading branch information
ryantxu committed Mar 29, 2019
2 parents 202c3ce + 6b2c81b commit 783cc20
Show file tree
Hide file tree
Showing 45 changed files with 662 additions and 318 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
@@ -1,6 +1,6 @@
# 6.1.0 (unreleased)

# 6.1.0-beta1 (unreleased)
# 6.1.0-beta1 (2019-03-27)

### New Features
* **Prometheus**: adhoc filter support [#8253](https://github.com/grafana/grafana/issues/8253), thx [@mtanda](https://github.com/mtanda)
Expand Down
12 changes: 11 additions & 1 deletion conf/defaults.ini
Expand Up @@ -141,7 +141,7 @@ cookie_name = grafana_sess
# If you use session in https only, default is false
cookie_secure = false

# Session life time, default is 86400
# Session life time, default is 86400 (means 86400 seconds or 24 hours)
session_life_time = 86400
gc_interval_time = 86400

Expand Down Expand Up @@ -521,6 +521,16 @@ nodata_or_nullvalues = no_data
# This limit will protect the server from render overloading and make sure notifications are sent out quickly
concurrent_render_limit = 5

# Default setting for alert calculation timeout. Default value is 30
evaluation_timeout_seconds = 30

# Default setting for alert notification timeout. Default value is 30
notification_timeout_seconds = 30

# Default setting for max attempts to sending alert notifications. Default value is 3
max_attempts = 3


#################################### Explore #############################
[explore]
# Enable the Explore section
Expand Down
12 changes: 11 additions & 1 deletion conf/sample.ini
Expand Up @@ -132,7 +132,7 @@ log_queries =
# If you use session in https only, default is false
;cookie_secure = false

# Session life time, default is 86400
# Session life time, default is 86400 (means 86400 seconds or 24 hours)
;session_life_time = 86400

#################################### Data proxy ###########################
Expand Down Expand Up @@ -446,6 +446,16 @@ log_queries =
# This limit will protect the server from render overloading and make sure notifications are sent out quickly
;concurrent_render_limit = 5


# Default setting for alert calculation timeout. Default value is 30
;evaluation_timeout_seconds = 30

# Default setting for alert notification timeout. Default value is 30
;notification_timeout_seconds = 30

# Default setting for max attempts to sending alert notifications. Default value is 3
;max_attempts = 3

#################################### Explore #############################
[explore]
# Enable the Explore section
Expand Down
10 changes: 6 additions & 4 deletions docs/sources/http_api/alerting_notification_channels.md
Expand Up @@ -152,6 +152,7 @@ Content-Type: application/json
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
{
"uid": "new-alert-notification", // optional
"name": "new alert notification", //Required
"type": "email", //Required
"isDefault": false,
Expand All @@ -170,7 +171,7 @@ Content-Type: application/json
{
"id": 1,
"uid": "cIBgcSjkk",
"uid": "new-alert-notification",
"name": "new alert notification",
"type": "email",
"isDefault": false,
Expand Down Expand Up @@ -198,6 +199,7 @@ Content-Type: application/json
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
{
"uid": "new-alert-notification", // optional
"name": "new alert notification", //Required
"type": "email", //Required
"isDefault": false,
Expand All @@ -217,7 +219,7 @@ Content-Type: application/json
{
"id": 1,
"uid": "cIBgcSjkk",
"uid": "new-alert-notification",
"name": "new alert notification",
"type": "email",
"isDefault": false,
Expand Down Expand Up @@ -247,7 +249,7 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
{
"id": 1,
"uid": "cIBgcSjkk",
"uid": "new-alert-notification", // optional
"name": "new alert notification", //Required
"type": "email", //Required
"isDefault": false,
Expand All @@ -267,7 +269,7 @@ Content-Type: application/json
{
"id": 1,
"uid": "cIBgcSjkk",
"uid": "new-alert-notification",
"name": "new alert notification",
"type": "email",
"isDefault": false,
Expand Down
14 changes: 14 additions & 0 deletions docs/sources/installation/configuration.md
Expand Up @@ -650,6 +650,20 @@ Alert notifications can include images, but rendering many images at the same ti
This limit will protect the server from render overloading and make sure notifications are sent out quickly. Default
value is `5`.


### evaluation_timeout_seconds

Default setting for alert calculation timeout. Default value is `30`

### notification_timeout_seconds

Default setting for alert notification timeout. Default value is `30`

### max_attempts

Default setting for max attempts to sending alert notifications. Default value is `3`


## [panels]

### enable_alpha
Expand Down
2 changes: 1 addition & 1 deletion packages/grafana-ui/src/components/Input/Input.tsx
Expand Up @@ -72,7 +72,7 @@ export class Input extends PureComponent<Props> {
const inputElementProps = this.populateEventPropsWithStatus(restProps, validationEvents);

return (
<div>
<div style={{ flexGrow: 1 }}>
<input {...inputElementProps} className={inputClassName} />
{error && !hideErrorMessage && <span>{error}</span>}
</div>
Expand Down
@@ -1,7 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Input renders correctly 1`] = `
<div>
<div
style={
Object {
"flexGrow": 1,
}
}
>
<input
className="gf-form-input"
/>
Expand Down
3 changes: 1 addition & 2 deletions packages/grafana-ui/src/components/Switch/Switch.tsx
@@ -1,6 +1,5 @@
import React, { PureComponent } from 'react';
import uniqueId from 'lodash/uniqueId';
import { Input } from '@grafana/ui';

export interface Props {
label: string;
Expand Down Expand Up @@ -39,7 +38,7 @@ export class Switch extends PureComponent<Props, State> {
<label htmlFor={labelId} className={`gf-form gf-form-switch-container ${className || ''}`}>
{label && <div className={labelClassName}>{label}</div>}
<div className={switchClassName}>
<Input id={labelId} type="checkbox" checked={checked} onChange={this.internalOnChange} />
<input id={labelId} type="checkbox" checked={checked} onChange={this.internalOnChange} />
<span className="gf-form-switch__slider" />
</div>
</label>
Expand Down
Expand Up @@ -467,7 +467,13 @@ exports[`Render should render with base threshold 1`] = `
type="text"
value="Base"
>
<div>
<div
style={
Object {
"flexGrow": 1,
}
}
>
<input
className="gf-form-input"
readOnly={true}
Expand Down
5 changes: 3 additions & 2 deletions packages/grafana-ui/src/types/data.ts
Expand Up @@ -21,15 +21,15 @@ export interface Field {
dateFormat?: string; // Source data format
}

export interface Tags {
export interface Labels {
[key: string]: string;
}

export interface SeriesData {
name?: string;
fields: Field[];
rows: any[][];
tags?: Tags;
labels?: Labels;
}

export interface Column {
Expand All @@ -51,6 +51,7 @@ export interface TimeSeries {
target: string;
datapoints: TimeSeriesPoints;
unit?: string;
tags?: Labels;
}

export enum NullValueMode {
Expand Down
7 changes: 6 additions & 1 deletion packages/grafana-ui/src/types/datasource.ts
Expand Up @@ -2,7 +2,12 @@ import { TimeRange, RawTimeRange } from './time';
import { PluginMeta } from './plugin';
import { TableData, TimeSeries, SeriesData } from './data';

export type DataQueryResponseData = TimeSeries | TableData | SeriesData | any;
/**
* Starting in v6.2 SeriesData can represent both TimeSeries and TableData
*/
export type LegacyResponseData = TimeSeries | TableData | any;

export type DataQueryResponseData = SeriesData | LegacyResponseData;

export interface DataQueryResponse {
data: DataQueryResponseData[];
Expand Down
1 change: 1 addition & 0 deletions packages/grafana-ui/src/types/index.ts
Expand Up @@ -7,4 +7,5 @@ export * from './theme';
export * from './graph';
export * from './threshold';
export * from './input';
export * from './logs';
export * from './displayValue';
21 changes: 21 additions & 0 deletions packages/grafana-ui/src/types/logs.ts
@@ -0,0 +1,21 @@
/**
* Mapping of log level abbreviation to canonical log level.
* Supported levels are reduce to limit color variation.
*/
export enum LogLevel {
emerg = 'critical',
alert = 'critical',
crit = 'critical',
critical = 'critical',
warn = 'warning',
warning = 'warning',
err = 'error',
eror = 'error',
error = 'error',
info = 'info',
notice = 'info',
dbug = 'debug',
debug = 'debug',
trace = 'trace',
unknown = 'unknown',
}
2 changes: 2 additions & 0 deletions packages/grafana-ui/src/utils/index.ts
Expand Up @@ -8,5 +8,7 @@ export * from './csv';
export * from './statsCalculator';
export * from './displayValue';
export * from './deprecationWarning';
export * from './logs';
export * from './labels';
export { getMappedValue } from './valueMappings';
export * from './validate';
55 changes: 55 additions & 0 deletions packages/grafana-ui/src/utils/labels.test.ts
@@ -0,0 +1,55 @@
import { parseLabels, formatLabels, findCommonLabels, findUniqueLabels } from './labels';

describe('parseLabels()', () => {
it('returns no labels on empty labels string', () => {
expect(parseLabels('')).toEqual({});
expect(parseLabels('{}')).toEqual({});
});

it('returns labels on labels string', () => {
expect(parseLabels('{foo="bar", baz="42"}')).toEqual({ foo: 'bar', baz: '42' });
});
});

describe('formatLabels()', () => {
it('returns no labels on empty label set', () => {
expect(formatLabels({})).toEqual('');
expect(formatLabels({}, 'foo')).toEqual('foo');
});

it('returns label string on label set', () => {
expect(formatLabels({ foo: 'bar', baz: '42' })).toEqual('{baz="42", foo="bar"}');
});
});

describe('findCommonLabels()', () => {
it('returns no common labels on empty sets', () => {
expect(findCommonLabels([{}])).toEqual({});
expect(findCommonLabels([{}, {}])).toEqual({});
});

it('returns no common labels on differing sets', () => {
expect(findCommonLabels([{ foo: 'bar' }, {}])).toEqual({});
expect(findCommonLabels([{}, { foo: 'bar' }])).toEqual({});
expect(findCommonLabels([{ baz: '42' }, { foo: 'bar' }])).toEqual({});
expect(findCommonLabels([{ foo: '42', baz: 'bar' }, { foo: 'bar' }])).toEqual({});
});

it('returns the single labels set as common labels', () => {
expect(findCommonLabels([{ foo: 'bar' }])).toEqual({ foo: 'bar' });
});
});

describe('findUniqueLabels()', () => {
it('returns no uncommon labels on empty sets', () => {
expect(findUniqueLabels({}, {})).toEqual({});
});

it('returns all labels given no common labels', () => {
expect(findUniqueLabels({ foo: '"bar"' }, {})).toEqual({ foo: '"bar"' });
});

it('returns all labels except the common labels', () => {
expect(findUniqueLabels({ foo: '"bar"', baz: '"42"' }, { foo: '"bar"' })).toEqual({ baz: '"42"' });
});
});
75 changes: 75 additions & 0 deletions packages/grafana-ui/src/utils/labels.ts
@@ -0,0 +1,75 @@
import { Labels } from '../types/data';

/**
* Regexp to extract Prometheus-style labels
*/
const labelRegexp = /\b(\w+)(!?=~?)"([^"\n]*?)"/g;

/**
* Returns a map of label keys to value from an input selector string.
*
* Example: `parseLabels('{job="foo", instance="bar"}) // {job: "foo", instance: "bar"}`
*/
export function parseLabels(labels: string): Labels {
const labelsByKey: Labels = {};
labels.replace(labelRegexp, (_, key, operator, value) => {
labelsByKey[key] = value;
return '';
});
return labelsByKey;
}

/**
* Returns a map labels that are common to the given label sets.
*/
export function findCommonLabels(labelsSets: Labels[]): Labels {
return labelsSets.reduce(
(acc, labels) => {
if (!labels) {
throw new Error('Need parsed labels to find common labels.');
}
if (!acc) {
// Initial set
acc = { ...labels };
} else {
// Remove incoming labels that are missing or not matching in value
Object.keys(labels).forEach(key => {
if (acc[key] === undefined || acc[key] !== labels[key]) {
delete acc[key];
}
});
// Remove common labels that are missing from incoming label set
Object.keys(acc).forEach(key => {
if (labels[key] === undefined) {
delete acc[key];
}
});
}
return acc;
},
(undefined as unknown) as Labels
);
}

/**
* Returns a map of labels that are in `labels`, but not in `commonLabels`.
*/
export function findUniqueLabels(labels: Labels, commonLabels: Labels): Labels {
const uncommonLabels: Labels = { ...labels };
Object.keys(commonLabels).forEach(key => {
delete uncommonLabels[key];
});
return uncommonLabels;
}

/**
* Serializes the given labels to a string.
*/
export function formatLabels(labels: Labels, defaultValue = ''): string {
if (!labels || Object.keys(labels).length === 0) {
return defaultValue;
}
const labelKeys = Object.keys(labels).sort();
const cleanSelector = labelKeys.map(key => `${key}="${labels[key]}"`).join(', ');
return ['{', cleanSelector, '}'].join('');
}

0 comments on commit 783cc20

Please sign in to comment.