logs_model.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import _ from 'lodash';
  2. import { TimeSeries } from 'app/core/core';
  3. import colors from 'app/core/utils/colors';
  4. export enum LogLevel {
  5. crit = 'crit',
  6. warn = 'warn',
  7. err = 'error',
  8. error = 'error',
  9. info = 'info',
  10. debug = 'debug',
  11. trace = 'trace',
  12. none = 'none',
  13. }
  14. export const LogLevelColor = {
  15. [LogLevel.crit]: colors[7],
  16. [LogLevel.warn]: colors[1],
  17. [LogLevel.err]: colors[4],
  18. [LogLevel.error]: colors[4],
  19. [LogLevel.info]: colors[0],
  20. [LogLevel.debug]: colors[3],
  21. [LogLevel.trace]: colors[3],
  22. [LogLevel.none]: '#eee',
  23. };
  24. export interface LogSearchMatch {
  25. start: number;
  26. length: number;
  27. text: string;
  28. }
  29. export interface LogRow {
  30. duplicates?: number;
  31. entry: string;
  32. key: string; // timestamp + labels
  33. labels: string;
  34. logLevel: LogLevel;
  35. searchWords?: string[];
  36. timestamp: string; // ISO with nanosec precision
  37. timeFromNow: string;
  38. timeEpochMs: number;
  39. timeLocal: string;
  40. uniqueLabels?: string;
  41. }
  42. export interface LogsMetaItem {
  43. label: string;
  44. value: string;
  45. }
  46. export interface LogsModel {
  47. meta?: LogsMetaItem[];
  48. rows: LogRow[];
  49. series?: TimeSeries[];
  50. }
  51. export interface LogsStream {
  52. labels: string;
  53. entries: LogsStreamEntry[];
  54. search?: string;
  55. parsedLabels?: LogsStreamLabels;
  56. uniqueLabels?: string;
  57. }
  58. export interface LogsStreamEntry {
  59. line: string;
  60. timestamp: string;
  61. }
  62. export interface LogsStreamLabels {
  63. [key: string]: string;
  64. }
  65. export enum LogsDedupStrategy {
  66. none = 'none',
  67. exact = 'exact',
  68. numbers = 'numbers',
  69. signature = 'signature',
  70. }
  71. const isoDateRegexp = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-6]\d[,\.]\d+([+-][0-2]\d:[0-5]\d|Z)/g;
  72. function isDuplicateRow(row: LogRow, other: LogRow, strategy: LogsDedupStrategy): boolean {
  73. switch (strategy) {
  74. case LogsDedupStrategy.exact:
  75. // Exact still strips dates
  76. return row.entry.replace(isoDateRegexp, '') === other.entry.replace(isoDateRegexp, '');
  77. case LogsDedupStrategy.numbers:
  78. return row.entry.replace(/\d/g, '') === other.entry.replace(/\d/g, '');
  79. case LogsDedupStrategy.signature:
  80. return row.entry.replace(/\w/g, '') === other.entry.replace(/\w/g, '');
  81. default:
  82. return false;
  83. }
  84. }
  85. export function dedupLogRows(logs: LogsModel, strategy: LogsDedupStrategy): LogsModel {
  86. if (strategy === LogsDedupStrategy.none) {
  87. return logs;
  88. }
  89. const dedupedRows = logs.rows.reduce((result: LogRow[], row: LogRow, index, list) => {
  90. const previous = result[result.length - 1];
  91. if (index > 0 && isDuplicateRow(row, previous, strategy)) {
  92. previous.duplicates++;
  93. } else {
  94. row.duplicates = 0;
  95. result.push(row);
  96. }
  97. return result;
  98. }, []);
  99. return {
  100. ...logs,
  101. rows: dedupedRows,
  102. };
  103. }
  104. export function makeSeriesForLogs(rows: LogRow[], intervalMs: number): TimeSeries[] {
  105. // Graph time series by log level
  106. const seriesByLevel = {};
  107. rows.forEach(row => {
  108. if (!seriesByLevel[row.logLevel]) {
  109. seriesByLevel[row.logLevel] = { lastTs: null, datapoints: [], alias: row.logLevel };
  110. }
  111. const levelSeries = seriesByLevel[row.logLevel];
  112. // Bucket to nearest minute
  113. const time = Math.round(row.timeEpochMs / intervalMs / 10) * intervalMs * 10;
  114. // Entry for time
  115. if (time === levelSeries.lastTs) {
  116. levelSeries.datapoints[levelSeries.datapoints.length - 1][0]++;
  117. } else {
  118. levelSeries.datapoints.push([1, time]);
  119. levelSeries.lastTs = time;
  120. }
  121. });
  122. return Object.keys(seriesByLevel).reduce((acc, level) => {
  123. if (seriesByLevel[level]) {
  124. const gs = new TimeSeries(seriesByLevel[level]);
  125. gs.setColor(LogLevelColor[level]);
  126. acc.push(gs);
  127. }
  128. return acc;
  129. }, []);
  130. }