LogsCheatSheet.tsx 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. import { css, cx } from '@emotion/css';
  2. import { stripIndent, stripIndents } from 'common-tags';
  3. import Prism from 'prismjs';
  4. import React, { PureComponent } from 'react';
  5. import { QueryEditorHelpProps } from '@grafana/data';
  6. import { flattenTokens } from '@grafana/ui/src/slate-plugins/slate-prism';
  7. import tokenizer from '../syntax';
  8. import { CloudWatchQuery } from '../types';
  9. interface QueryExample {
  10. category: string;
  11. examples: Array<{
  12. title: string;
  13. expr: string;
  14. }>;
  15. }
  16. const CLIQ_EXAMPLES: QueryExample[] = [
  17. {
  18. category: 'Lambda',
  19. examples: [
  20. {
  21. title: 'View latency statistics for 5-minute intervals',
  22. expr: stripIndents`filter @type = "REPORT" |
  23. stats avg(@duration), max(@duration), min(@duration) by bin(5m)`,
  24. },
  25. {
  26. title: 'Determine the amount of overprovisioned memory',
  27. expr: stripIndent`
  28. filter @type = "REPORT" |
  29. stats max(@memorySize / 1024 / 1024) as provisonedMemoryMB,
  30. min(@maxMemoryUsed / 1024 / 1024) as smallestMemoryRequestMB,
  31. avg(@maxMemoryUsed / 1024 / 1024) as avgMemoryUsedMB,
  32. max(@maxMemoryUsed / 1024 / 1024) as maxMemoryUsedMB,
  33. provisonedMemoryMB - maxMemoryUsedMB as overProvisionedMB`,
  34. },
  35. {
  36. title: 'Find the most expensive requests',
  37. expr: stripIndents`filter @type = "REPORT" |
  38. fields @requestId, @billedDuration |
  39. sort by @billedDuration desc`,
  40. },
  41. ],
  42. },
  43. {
  44. category: 'VPC Flow Logs',
  45. examples: [
  46. {
  47. title: 'Average, min, and max byte transfers by source and destination IP addresses',
  48. expr: `stats avg(bytes), min(bytes), max(bytes) by srcAddr, dstAddr`,
  49. },
  50. {
  51. title: 'IP addresses using UDP transfer protocol',
  52. expr: 'filter protocol=17 | stats count(*) by srcAddr',
  53. },
  54. {
  55. title: 'Top 10 byte transfers by source and destination IP addresses',
  56. expr: stripIndents`stats sum(bytes) as bytesTransferred by srcAddr, dstAddr |
  57. sort bytesTransferred desc |
  58. limit 10`,
  59. },
  60. {
  61. title: 'Top 20 source IP addresses with highest number of rejected requests',
  62. expr: stripIndents`filter action="REJECT" |
  63. stats count(*) as numRejections by srcAddr |
  64. sort numRejections desc |
  65. limit 20`,
  66. },
  67. ],
  68. },
  69. {
  70. category: 'CloudTrail',
  71. examples: [
  72. {
  73. title: 'Number of log entries by service, event type, and region',
  74. expr: 'stats count(*) by eventSource, eventName, awsRegion',
  75. },
  76. {
  77. title: 'Number of log entries by region and EC2 event type',
  78. expr: stripIndents`filter eventSource="ec2.amazonaws.com" |
  79. stats count(*) as eventCount by eventName, awsRegion |
  80. sort eventCount desc`,
  81. },
  82. {
  83. title: 'Regions, usernames, and ARNs of newly created IAM users',
  84. expr: stripIndents`filter eventName="CreateUser" |
  85. fields awsRegion, requestParameters.userName, responseElements.user.arn`,
  86. },
  87. ],
  88. },
  89. {
  90. category: 'Common Queries',
  91. examples: [
  92. {
  93. title: '25 most recently added log events',
  94. expr: stripIndents`fields @timestamp, @message |
  95. sort @timestamp desc |
  96. limit 25`,
  97. },
  98. {
  99. title: 'Number of exceptions logged every 5 minutes',
  100. expr: stripIndents`filter @message like /Exception/ |
  101. stats count(*) as exceptionCount by bin(5m) |
  102. sort exceptionCount desc`,
  103. },
  104. {
  105. title: 'List of log events that are not exceptions',
  106. expr: 'fields @message | filter @message not like /Exception/',
  107. },
  108. ],
  109. },
  110. {
  111. category: 'Route 53',
  112. examples: [
  113. {
  114. title: 'Number of requests received every 10 minutes by edge location',
  115. expr: 'stats count(*) by queryType, bin(10m)',
  116. },
  117. {
  118. title: 'Number of unsuccessful requests by domain',
  119. expr: 'filter responseCode="SERVFAIL" | stats count(*) by queryName',
  120. },
  121. {
  122. title: 'Number of requests received every 10 minutes by edge location',
  123. expr: 'stats count(*) as numRequests by resolverIp | sort numRequests desc | limit 10',
  124. },
  125. ],
  126. },
  127. {
  128. category: 'AWS AppSync',
  129. examples: [
  130. {
  131. title: 'Number of unique HTTP status codes',
  132. expr: stripIndents`fields ispresent(graphQLAPIId) as isApi |
  133. filter isApi |
  134. filter logType = "RequestSummary" |
  135. stats count() as statusCount by statusCode |
  136. sort statusCount desc`,
  137. },
  138. {
  139. title: 'Top 10 resolvers with maximum latency',
  140. expr: stripIndents`fields resolverArn, duration |
  141. filter logType = "Tracing" |
  142. sort duration desc |
  143. limit 10`,
  144. },
  145. {
  146. title: 'Most frequently invoked resolvers',
  147. expr: stripIndents`fields ispresent(resolverArn) as isRes |
  148. stats count() as invocationCount by resolverArn |
  149. filter isRes |
  150. filter logType = "Tracing" |
  151. sort invocationCount desc |
  152. limit 10`,
  153. },
  154. {
  155. title: 'Resolvers with most errors in mapping templates',
  156. expr: stripIndents`fields ispresent(resolverArn) as isRes |
  157. stats count() as errorCount by resolverArn, logType |
  158. filter isRes and (logType = "RequestMapping" or logType = "ResponseMapping") and fieldInError |
  159. sort errorCount desc |
  160. limit 10`,
  161. },
  162. {
  163. title: 'Field latency statistics',
  164. expr: stripIndents`fields requestId, latency |
  165. filter logType = "RequestSummary" |
  166. sort latency desc |
  167. limit 10`,
  168. },
  169. {
  170. title: 'Resolver latency statistics',
  171. expr: stripIndents`fields ispresent(resolverArn) as isRes |
  172. filter isRes |
  173. filter logType = "Tracing" |
  174. stats min(duration), max(duration), avg(duration) as avgDur by resolverArn |
  175. sort avgDur desc |
  176. limit 10`,
  177. },
  178. {
  179. title: 'Top 10 requests with maximum latency',
  180. expr: stripIndents`fields requestId, latency |
  181. filter logType = "RequestSummary" |
  182. sort latency desc |
  183. limit 10`,
  184. },
  185. ],
  186. },
  187. ];
  188. function renderHighlightedMarkup(code: string, keyPrefix: string) {
  189. const grammar = tokenizer;
  190. const tokens = flattenTokens(Prism.tokenize(code, grammar));
  191. const spans = tokens
  192. .filter((token) => typeof token !== 'string')
  193. .map((token, i) => {
  194. return (
  195. <span
  196. className={`prism-token token ${token.types.join(' ')} ${token.aliases.join(' ')}`}
  197. key={`${keyPrefix}-token-${i}`}
  198. >
  199. {token.content}
  200. </span>
  201. );
  202. });
  203. return <div className="slate-query-field">{spans}</div>;
  204. }
  205. const exampleCategory = css`
  206. margin-top: 5px;
  207. `;
  208. export default class LogsCheatSheet extends PureComponent<
  209. QueryEditorHelpProps<CloudWatchQuery>,
  210. { userExamples: string[] }
  211. > {
  212. onClickExample(query: CloudWatchQuery) {
  213. this.props.onClickExample(query);
  214. }
  215. renderExpression(expr: string, keyPrefix: string) {
  216. return (
  217. <div
  218. className="cheat-sheet-item__example"
  219. key={expr}
  220. onClick={() =>
  221. this.onClickExample({
  222. refId: this.props.query.refId ?? 'A',
  223. expression: expr,
  224. queryMode: 'Logs',
  225. region: this.props.query.region,
  226. id: this.props.query.refId ?? 'A',
  227. logGroupNames: 'logGroupNames' in this.props.query ? this.props.query.logGroupNames : [],
  228. })
  229. }
  230. >
  231. <pre>{renderHighlightedMarkup(expr, keyPrefix)}</pre>
  232. </div>
  233. );
  234. }
  235. renderLogsCheatSheet() {
  236. return (
  237. <div>
  238. <h2>CloudWatch Logs Cheat Sheet</h2>
  239. {CLIQ_EXAMPLES.map((cat, i) => (
  240. <div key={`${cat.category}-${i}`}>
  241. <div className={`cheat-sheet-item__title ${cx(exampleCategory)}`}>{cat.category}</div>
  242. {cat.examples.map((item, j) => (
  243. <div className="cheat-sheet-item" key={`item-${j}`}>
  244. <h4>{item.title}</h4>
  245. {this.renderExpression(item.expr, `item-${j}`)}
  246. </div>
  247. ))}
  248. </div>
  249. ))}
  250. </div>
  251. );
  252. }
  253. render() {
  254. return (
  255. <div>
  256. <h3>CloudWatch Logs cheat sheet</h3>
  257. {CLIQ_EXAMPLES.map((cat, i) => (
  258. <div key={`cat-${i}`}>
  259. <div className={`cheat-sheet-item__title ${cx(exampleCategory)}`}>{cat.category}</div>
  260. {cat.examples.map((item, j) => (
  261. <div className="cheat-sheet-item" key={`item-${j}`}>
  262. <h4>{item.title}</h4>
  263. {this.renderExpression(item.expr, `item-${j}`)}
  264. </div>
  265. ))}
  266. </div>
  267. ))}
  268. </div>
  269. );
  270. }
  271. }