mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Improve error handling for Graphite 0.9 and 1.0 (#32642)
This commit is contained in:
parent
5e1d0a8851
commit
0d08928981
@ -19,9 +19,10 @@ import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_sr
|
||||
import { GraphiteOptions, GraphiteQuery, GraphiteType, MetricTankRequestMeta } from './types';
|
||||
import { getRollupNotice, getRuntimeConsolidationNotice } from 'app/plugins/datasource/graphite/meta';
|
||||
import { getSearchFilterScopedVar } from '../../../features/variables/utils';
|
||||
import { Observable, of, OperatorFunction, pipe } from 'rxjs';
|
||||
import { Observable, of, OperatorFunction, pipe, throwError } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { DEFAULT_GRAPHITE_VERSION } from './versions';
|
||||
import { reduceError } from './utils';
|
||||
|
||||
export class GraphiteDatasource extends DataSourceApi<GraphiteQuery, GraphiteOptions> {
|
||||
basicAuth: string;
|
||||
@ -645,7 +646,13 @@ export class GraphiteDatasource extends DataSourceApi<GraphiteQuery, GraphiteOpt
|
||||
options.url = this.url + options.url;
|
||||
options.inspect = { type: 'graphite' };
|
||||
|
||||
return getBackendSrv().fetch(options);
|
||||
return getBackendSrv()
|
||||
.fetch(options)
|
||||
.pipe(
|
||||
catchError((err: any) => {
|
||||
return throwError(reduceError(err));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
buildGraphiteParams(options: any, scopedVars?: ScopedVars): string[] {
|
||||
|
90
public/app/plugins/datasource/graphite/utils.test.ts
Normal file
90
public/app/plugins/datasource/graphite/utils.test.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import { reduceError } from './utils';
|
||||
|
||||
const SAMPLE_500_PAGE = `<body style="background-color: #666666; color: black;">
|
||||
<center>
|
||||
<h2 style='font-family: "Arial"'>
|
||||
<p>Graphite encountered an unexpected error while handling your request.</p>
|
||||
<p>Please contact your site administrator if the problem persists.</p>
|
||||
</h2>
|
||||
<br/>
|
||||
<div style="width: 50%; text-align: center; font-family: monospace; background-color: black; font-weight: bold; color: #ff4422;">
|
||||
|
||||
</div>
|
||||
|
||||
<div style="width: 70%; text-align: left; background-color: black; color: #44ff22; border: thin solid gray;">
|
||||
<pre>
|
||||
Traceback (most recent call last):
|
||||
File "/usr/lib/python2.7/dist-packages/django/core/handlers/base.py", line 112, in get_response
|
||||
response = wrapped_callback(request, *callback_args, **callback_kwargs)
|
||||
File "/var/lib/graphite/webapp/graphite/render/views.py", line 125, in renderView
|
||||
seriesList = evaluateTarget(requestContext, target)
|
||||
File "/var/lib/graphite/webapp/graphite/render/evaluator.py", line 10, in evaluateTarget
|
||||
result = evaluateTokens(requestContext, tokens)
|
||||
File "/var/lib/graphite/webapp/graphite/render/evaluator.py", line 21, in evaluateTokens
|
||||
return evaluateTokens(requestContext, tokens.expression)
|
||||
File "/var/lib/graphite/webapp/graphite/render/evaluator.py", line 27, in evaluateTokens
|
||||
func = SeriesFunctions[tokens.call.func]
|
||||
KeyError: u'aliasByNodde'
|
||||
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
</center>
|
||||
`;
|
||||
|
||||
describe('Graphite utils', () => {
|
||||
it('should reduce HTML based errors', () => {
|
||||
const error = {
|
||||
status: 500,
|
||||
data: {
|
||||
message: SAMPLE_500_PAGE,
|
||||
},
|
||||
};
|
||||
|
||||
expect(reduceError(error)).toMatchObject({
|
||||
data: {
|
||||
message: 'Graphite encountered an unexpected error while handling your request. KeyError: aliasByNodde',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return original error for non-HTML 500 error pages', () => {
|
||||
const error = {
|
||||
status: 500,
|
||||
data: {
|
||||
message: 'ERROR MESSAGE',
|
||||
},
|
||||
};
|
||||
|
||||
expect(reduceError(error)).toMatchObject({
|
||||
data: {
|
||||
message: 'ERROR MESSAGE',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return original error for non 500 errors', () => {
|
||||
const error = {
|
||||
status: 400,
|
||||
data: {
|
||||
message: 'ERROR MESSAGE',
|
||||
},
|
||||
};
|
||||
|
||||
expect(reduceError(error)).toMatchObject({
|
||||
data: {
|
||||
message: 'ERROR MESSAGE',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return original error for errors other than FetchError (not data property)', () => {
|
||||
const error = {
|
||||
message: 'ERROR MESSAGE',
|
||||
};
|
||||
|
||||
expect(reduceError(error)).toMatchObject({
|
||||
message: 'ERROR MESSAGE',
|
||||
});
|
||||
});
|
||||
});
|
21
public/app/plugins/datasource/graphite/utils.ts
Normal file
21
public/app/plugins/datasource/graphite/utils.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
/**
|
||||
* Graphite-web before v1.6 returns HTTP 500 with full stack traces in an HTML page
|
||||
* when a query fails. It results in massive error alerts with HTML tags in the UI.
|
||||
* This function removes all HTML tags and keeps only the last line from the stack
|
||||
* trace which should be the most meaningful.
|
||||
*/
|
||||
export function reduceError(error: any): any {
|
||||
if (error && error.status === 500 && error.data?.message?.startsWith('<body')) {
|
||||
// Remove all HTML tags and take the last line from the stack trace
|
||||
const newMessage = _.last<string>(
|
||||
error.data.message
|
||||
.replace(/(<([^>]+)>)/gi, '')
|
||||
.trim()
|
||||
.split(/\n/)
|
||||
)!.replace(/u?&#[^;]+;/g, '');
|
||||
error.data.message = `Graphite encountered an unexpected error while handling your request. ${newMessage}`;
|
||||
}
|
||||
return error;
|
||||
}
|
Loading…
Reference in New Issue
Block a user