grafana/public/app/plugins/datasource/cloudwatch/components/LogsCheatSheet.tsx
Torkel Ödegaard 863b412d54
Transformations: State feature (alpha/beta) and more (#36630)
* Adding plugin state feature to transforms

* initial help box

* New HelpBox component

* More progress

* Testing

* Removing HelpBox, simple new design, new active state for OperationRowAction

* Updated tests

* Fixed typing issue

* Removed AlphaNotice

* Made focus and enter key trigger OnClick and sorted transformations

* Fixed e2e tests
2021-07-12 16:42:04 +02:00

277 lines
9.2 KiB
TypeScript

import React, { PureComponent } from 'react';
import { stripIndent, stripIndents } from 'common-tags';
import { QueryEditorHelpProps } from '@grafana/data';
import Prism from 'prismjs';
import tokenizer from '../syntax';
import { flattenTokens } from '@grafana/ui/src/slate-plugins/slate-prism';
import { css, cx } from '@emotion/css';
import { CloudWatchQuery } from '../types';
interface QueryExample {
category: string;
examples: Array<{
title: string;
expr: string;
}>;
}
const CLIQ_EXAMPLES: QueryExample[] = [
{
category: 'Lambda',
examples: [
{
title: 'View latency statistics for 5-minute intervals',
expr: stripIndents`filter @type = "REPORT" |
stats avg(@duration), max(@duration), min(@duration) by bin(5m)`,
},
{
title: 'Determine the amount of overprovisioned memory',
expr: stripIndent`
filter @type = "REPORT" |
stats max(@memorySize / 1024 / 1024) as provisonedMemoryMB,
min(@maxMemoryUsed / 1024 / 1024) as smallestMemoryRequestMB,
avg(@maxMemoryUsed / 1024 / 1024) as avgMemoryUsedMB,
max(@maxMemoryUsed / 1024 / 1024) as maxMemoryUsedMB,
provisonedMemoryMB - maxMemoryUsedMB as overProvisionedMB`,
},
{
title: 'Find the most expensive requests',
expr: stripIndents`filter @type = "REPORT" |
fields @requestId, @billedDuration |
sort by @billedDuration desc`,
},
],
},
{
category: 'VPC Flow Logs',
examples: [
{
title: 'Average, min, and max byte transfers by source and destination IP addresses',
expr: `stats avg(bytes), min(bytes), max(bytes) by srcAddr, dstAddr`,
},
{
title: 'IP addresses using UDP transfer protocol',
expr: 'filter protocol=17 | stats count(*) by srcAddr',
},
{
title: 'Top 10 byte transfers by source and destination IP addresses',
expr: stripIndents`stats sum(bytes) as bytesTransferred by srcAddr, dstAddr |
sort bytesTransferred desc |
limit 10`,
},
{
title: 'Top 20 source IP addresses with highest number of rejected requests',
expr: stripIndents`filter action="REJECT" |
stats count(*) as numRejections by srcAddr |
sort numRejections desc |
limit 20`,
},
],
},
{
category: 'CloudTrail',
examples: [
{
title: 'Number of log entries by service, event type, and region',
expr: 'stats count(*) by eventSource, eventName, awsRegion',
},
{
title: 'Number of log entries by region and EC2 event type',
expr: stripIndents`filter eventSource="ec2.amazonaws.com" |
stats count(*) as eventCount by eventName, awsRegion |
sort eventCount desc`,
},
{
title: 'Regions, usernames, and ARNs of newly created IAM users',
expr: stripIndents`filter eventName="CreateUser" |
fields awsRegion, requestParameters.userName, responseElements.user.arn`,
},
],
},
{
category: 'Common Queries',
examples: [
{
title: '25 most recently added log events',
expr: stripIndents`fields @timestamp, @message |
sort @timestamp desc |
limit 25`,
},
{
title: 'Number of exceptions logged every 5 minutes',
expr: stripIndents`filter @message like /Exception/ |
stats count(*) as exceptionCount by bin(5m) |
sort exceptionCount desc`,
},
{
title: 'List of log events that are not exceptions',
expr: 'fields @message | filter @message not like /Exception/',
},
],
},
{
category: 'Route 53',
examples: [
{
title: 'Number of requests received every 10 minutes by edge location',
expr: 'stats count(*) by queryType, bin(10m)',
},
{
title: 'Number of unsuccessful requests by domain',
expr: 'filter responseCode="SERVFAIL" | stats count(*) by queryName',
},
{
title: 'Number of requests received every 10 minutes by edge location',
expr: 'stats count(*) as numRequests by resolverIp | sort numRequests desc | limit 10',
},
],
},
{
category: 'AWS AppSync',
examples: [
{
title: 'Number of unique HTTP status codes',
expr: stripIndents`fields ispresent(graphQLAPIId) as isApi |
filter isApi |
filter logType = "RequestSummary" |
stats count() as statusCount by statusCode |
sort statusCount desc`,
},
{
title: 'Top 10 resolvers with maximum latency',
expr: stripIndents`fields resolverArn, duration |
filter logType = "Tracing" |
sort duration desc |
limit 10`,
},
{
title: 'Most frequently invoked resolvers',
expr: stripIndents`fields ispresent(resolverArn) as isRes |
stats count() as invocationCount by resolverArn |
filter isRes |
filter logType = "Tracing" |
sort invocationCount desc |
limit 10`,
},
{
title: 'Resolvers with most errors in mapping templates',
expr: stripIndents`fields ispresent(resolverArn) as isRes |
stats count() as errorCount by resolverArn, logType |
filter isRes and (logType = "RequestMapping" or logType = "ResponseMapping") and fieldInError |
sort errorCount desc |
limit 10`,
},
{
title: 'Field latency statistics',
expr: stripIndents`fields requestId, latency |
filter logType = "RequestSummary" |
sort latency desc |
limit 10`,
},
{
title: 'Resolver latency statistics',
expr: stripIndents`fields ispresent(resolverArn) as isRes |
filter isRes |
filter logType = "Tracing" |
stats min(duration), max(duration), avg(duration) as avgDur by resolverArn |
sort avgDur desc |
limit 10`,
},
{
title: 'Top 10 requests with maximum latency',
expr: stripIndents`fields requestId, latency |
filter logType = "RequestSummary" |
sort latency desc |
limit 10`,
},
],
},
];
function renderHighlightedMarkup(code: string, keyPrefix: string) {
const grammar = tokenizer;
const tokens = flattenTokens(Prism.tokenize(code, grammar));
const spans = tokens
.filter((token) => typeof token !== 'string')
.map((token, i) => {
return (
<span
className={`prism-token token ${token.types.join(' ')} ${token.aliases.join(' ')}`}
key={`${keyPrefix}-token-${i}`}
>
{token.content}
</span>
);
});
return <div className="slate-query-field">{spans}</div>;
}
const exampleCategory = css`
margin-top: 5px;
`;
export default class LogsCheatSheet extends PureComponent<
QueryEditorHelpProps<CloudWatchQuery>,
{ userExamples: string[] }
> {
onClickExample(query: CloudWatchQuery) {
this.props.onClickExample(query);
}
renderExpression(expr: string, keyPrefix: string) {
return (
<div
className="cheat-sheet-item__example"
key={expr}
onClick={(e) =>
this.onClickExample({ refId: 'A', expression: expr, queryMode: 'Logs', region: 'default', id: 'A' })
}
>
<pre>{renderHighlightedMarkup(expr, keyPrefix)}</pre>
</div>
);
}
renderLogsCheatSheet() {
return (
<div>
<h2>CloudWatch Logs Cheat Sheet</h2>
{CLIQ_EXAMPLES.map((cat, i) => (
<div key={`${cat.category}-${i}`}>
<div className={`cheat-sheet-item__title ${cx(exampleCategory)}`}>{cat.category}</div>
{cat.examples.map((item, j) => (
<div className="cheat-sheet-item" key={`item-${j}`}>
<h4>{item.title}</h4>
{this.renderExpression(item.expr, `item-${j}`)}
</div>
))}
</div>
))}
</div>
);
}
render() {
return (
<div>
<h3>CloudWatch Logs cheat sheet</h3>
{CLIQ_EXAMPLES.map((cat, i) => (
<div key={`cat-${i}`}>
<div className={`cheat-sheet-item__title ${cx(exampleCategory)}`}>{cat.category}</div>
{cat.examples.map((item, j) => (
<div className="cheat-sheet-item" key={`item-${j}`}>
<h4>{item.title}</h4>
{this.renderExpression(item.expr, `item-${j}`)}
</div>
))}
</div>
))}
</div>
);
}
}