mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Azure Monitor : Adding json formatting of error messages in Panel Header Corner and Inspect Error Tab (#44877)
* Trying out json formatting of azure graph err from frontend * Added some tests wip * Wrap text in popper tooltip * fix conflict * Wrap text in tooltip * Complete tests * Added invalid json test * Backend changes and tests * removed comments * Added split of message / json and edge cases tests * Addressed comments * moved catch to parseErrorMessage
This commit is contained in:
parent
dd9b52fd41
commit
530913dd37
@ -69,6 +69,7 @@ function getStyles(theme: GrafanaTheme2) {
|
|||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
z-index: ${theme.zIndex.tooltip};
|
z-index: ${theme.zIndex.tooltip};
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
|
||||||
&[data-popper-interactive='false'] {
|
&[data-popper-interactive='false'] {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
@ -235,7 +235,7 @@ func (e *AzureResourceGraphDatasource) unmarshalResponse(res *http.Response) (Az
|
|||||||
|
|
||||||
if res.StatusCode/100 != 2 {
|
if res.StatusCode/100 != 2 {
|
||||||
azlog.Debug("Request failed", "status", res.Status, "body", string(body))
|
azlog.Debug("Request failed", "status", res.Status, "body", string(body))
|
||||||
return AzureResourceGraphResponse{}, fmt.Errorf("request failed, status: %s, body: %s", res.Status, string(body))
|
return AzureResourceGraphResponse{}, fmt.Errorf("%s. Azure Resource Graph error: %s", res.Status, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
var data AzureResourceGraphResponse
|
var data AzureResourceGraphResponse
|
||||||
|
@ -2,7 +2,9 @@ package azuremonitor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -150,3 +152,46 @@ func TestGetAzurePortalUrl(t *testing.T) {
|
|||||||
assert.Equal(t, expectedAzurePortalUrl[cloud], azurePortalUrl)
|
assert.Equal(t, expectedAzurePortalUrl[cloud], azurePortalUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalResponse400(t *testing.T) {
|
||||||
|
datasource := &AzureResourceGraphDatasource{}
|
||||||
|
res, err := datasource.unmarshalResponse(&http.Response{
|
||||||
|
StatusCode: 400,
|
||||||
|
Status: "400 Bad Request",
|
||||||
|
Body: io.NopCloser(strings.NewReader(("Azure Error Message"))),
|
||||||
|
})
|
||||||
|
|
||||||
|
expectedErrMsg := "400 Bad Request. Azure Resource Graph error: Azure Error Message"
|
||||||
|
|
||||||
|
assert.Equal(t, expectedErrMsg, err.Error())
|
||||||
|
assert.Empty(t, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalResponse200Invalid(t *testing.T) {
|
||||||
|
datasource := &AzureResourceGraphDatasource{}
|
||||||
|
res, err := datasource.unmarshalResponse(&http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Status: "OK",
|
||||||
|
Body: io.NopCloser(strings.NewReader(("Azure Data"))),
|
||||||
|
})
|
||||||
|
|
||||||
|
expectedRes := AzureResourceGraphResponse{}
|
||||||
|
expectedErr := "invalid character 'A' looking for beginning of value"
|
||||||
|
|
||||||
|
assert.Equal(t, expectedErr, err.Error())
|
||||||
|
assert.Equal(t, expectedRes, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalResponse200(t *testing.T) {
|
||||||
|
datasource := &AzureResourceGraphDatasource{}
|
||||||
|
res, err2 := datasource.unmarshalResponse(&http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Status: "OK",
|
||||||
|
Body: io.NopCloser(strings.NewReader("{}")),
|
||||||
|
})
|
||||||
|
|
||||||
|
expectedRes := AzureResourceGraphResponse{}
|
||||||
|
|
||||||
|
assert.NoError(t, err2)
|
||||||
|
assert.Equal(t, expectedRes, res)
|
||||||
|
}
|
||||||
|
72
public/app/features/inspector/InspectErrorTab.test.tsx
Normal file
72
public/app/features/inspector/InspectErrorTab.test.tsx
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { InspectErrorTab } from './InspectErrorTab';
|
||||||
|
|
||||||
|
describe('InspectErrorTab', () => {
|
||||||
|
it('should return null when error does not exist', () => {
|
||||||
|
const { container } = render(<InspectErrorTab />);
|
||||||
|
expect(container.childElementCount).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a jsonFormatter object of error.data if it exists', () => {
|
||||||
|
const error = {
|
||||||
|
data: {
|
||||||
|
message: 'This is an error',
|
||||||
|
error: 'my error',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
render(<InspectErrorTab error={error} />);
|
||||||
|
expect(screen.getByText('This is an error')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('error:')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('"my error"')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a jsonFormatter object of error.message if it exists and data does not exist', () => {
|
||||||
|
const error = {
|
||||||
|
message:
|
||||||
|
'{ "error": { "code": "BadRequest", "message": "Please provide below info when asking for support.", "details": [] } }',
|
||||||
|
};
|
||||||
|
const { container } = render(<InspectErrorTab error={error} />);
|
||||||
|
expect(container.childElementCount).toEqual(1);
|
||||||
|
expect(screen.getByText('code:')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('"BadRequest"')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('"Please provide below info when asking for support."')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an h3 and jsonFormatter object of error.message if it exists and data does not exist', () => {
|
||||||
|
const error = {
|
||||||
|
message:
|
||||||
|
'400 BadRequest, Error from Azure: { "error": { "code": "BadRequest", "message": "Please provide below info when asking for support.", "details": [] } }',
|
||||||
|
};
|
||||||
|
const { container } = render(<InspectErrorTab error={error} />);
|
||||||
|
expect(container.childElementCount).toEqual(2);
|
||||||
|
expect(screen.getByRole('heading', { name: '400 BadRequest, Error from Azure:' })).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('code:')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('"BadRequest"')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
[
|
||||||
|
'{ invalidJSON{',
|
||||||
|
"hello, I am an error that's just text, no json at all, altoough I do mention template variables {{test}}",
|
||||||
|
'and I am a simple string',
|
||||||
|
].forEach((errMsg) => {
|
||||||
|
it(`should return error.message error.data does not exist nd error.message cannot be parsed - ${errMsg} `, () => {
|
||||||
|
const error = {
|
||||||
|
message: errMsg,
|
||||||
|
};
|
||||||
|
render(<InspectErrorTab error={error} />);
|
||||||
|
expect(screen.queryByRole('heading')).toBeNull();
|
||||||
|
expect(screen.getByText(errMsg)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a jsonFormatter object of error if it has no .data and no .message', () => {
|
||||||
|
const error = {
|
||||||
|
status: '400',
|
||||||
|
};
|
||||||
|
const { container } = render(<InspectErrorTab error={error} />);
|
||||||
|
expect(container.childElementCount).toEqual(1);
|
||||||
|
expect(screen.getByText('status:')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('"400"')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
@ -6,6 +6,19 @@ interface InspectErrorTabProps {
|
|||||||
error?: DataQueryError;
|
error?: DataQueryError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parseErrorMessage = (message: string): { msg: string; json?: any } => {
|
||||||
|
try {
|
||||||
|
const [msg, json] = message.split(/(\{.+)/);
|
||||||
|
const jsonError = JSON.parse(json);
|
||||||
|
return {
|
||||||
|
msg,
|
||||||
|
json: jsonError,
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return { msg: message };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const InspectErrorTab: React.FC<InspectErrorTabProps> = ({ error }) => {
|
export const InspectErrorTab: React.FC<InspectErrorTabProps> = ({ error }) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
return null;
|
return null;
|
||||||
@ -18,5 +31,18 @@ export const InspectErrorTab: React.FC<InspectErrorTabProps> = ({ error }) => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <div>{error.message}</div>;
|
if (error.message) {
|
||||||
|
const { msg, json } = parseErrorMessage(error.message);
|
||||||
|
if (!json) {
|
||||||
|
return <div>{msg}</div>;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{msg !== '' && <h3>{msg}</h3>}
|
||||||
|
<JSONFormatter json={json} open={5} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <JSONFormatter json={error} open={2} />;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user