From 313f0b2e9d4026af3a1ed7e20b5409e0061c8d41 Mon Sep 17 00:00:00 2001 From: Frank Dekker Date: Sat, 27 Jan 2024 22:36:26 +0100 Subject: [PATCH 01/14] Add level and channel search terms --- docs/advanced-search-queries.md | 11 +++++--- src/Entity/Expression/ChannelTerm.php | 16 +++++++++++ src/Entity/Expression/SeverityTerm.php | 16 +++++++++++ src/Resources/config/services.php | 4 +++ src/Service/Matcher/ChannelTermMatcher.php | 30 +++++++++++++++++++++ src/Service/Matcher/SeverityTermMatcher.php | 30 +++++++++++++++++++++ src/Service/Parser/ExpressionParser.php | 7 +++-- src/Service/Parser/TermParser.php | 11 +++++++- 8 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 src/Entity/Expression/ChannelTerm.php create mode 100644 src/Entity/Expression/SeverityTerm.php create mode 100644 src/Service/Matcher/ChannelTermMatcher.php create mode 100644 src/Service/Matcher/SeverityTermMatcher.php diff --git a/docs/advanced-search-queries.md b/docs/advanced-search-queries.md index bac4149f..9f2a531f 100644 --- a/docs/advanced-search-queries.md +++ b/docs/advanced-search-queries.md @@ -6,21 +6,24 @@ The search query allows for more fine-grained control over the search results. T |--------------------------------------|-------|---------------------------------------------------------------------------------| | `before:`,`before:""` | `b` | Show all logs messages that occur before the specified date. | | `after:`,`after:""` | `a` | Show all logs messages that occur after the specified date. | +| `severity:` | `s` | Show all logs messages that match the given severity/severities. | +| `channel:` | `c` | Show all logs messages that match the given channel(s). | +| `after:`,`after:""` | `a` | Show all logs messages that occur after the specified date. | | `exclude:`,`exclude:""` | `-` | Exclude the specific sentence from the results. Can be specified multiple times | ## Example -Search all log entries between `2020-01-01` and `2020-01-31`, excluding all entries that contain the word `"Controller"` and must -include `"Exception"`. +Search all log entries between `2020-01-01` and `2020-01-31`, for severity `warning` or `error`, in channel `app` +excluding all entries that contain the word `"Controller"` and must include `"Exception"`. ```text -before:2020-01-31 after:2020-01-01 exclude:Controller "Failed to read" +before:2020-01-31 after:2020-01-01 severity:warning|error channel:app exclude:Controller "Failed to read" ``` ### In shorthand ```text -b:2020-01-31 a:2020-01-01 -:Controller "Failed to read" +b:2020-01-31 a:2020-01-01 s:warning|error c:app -:Controller "Failed to read" ``` ### Multiple exclusions diff --git a/src/Entity/Expression/ChannelTerm.php b/src/Entity/Expression/ChannelTerm.php new file mode 100644 index 00000000..bd3a50c9 --- /dev/null +++ b/src/Entity/Expression/ChannelTerm.php @@ -0,0 +1,16 @@ +set(DateBeforeTermMatcher::class)->tag('fd.symfony.log.viewer.term_matcher'); $services->set(DateAfterTermMatcher::class)->tag('fd.symfony.log.viewer.term_matcher'); + $services->set(SeverityTermMatcher::class)->tag('fd.symfony.log.viewer.term_matcher'); + $services->set(ChannelTermMatcher::class)->tag('fd.symfony.log.viewer.term_matcher'); $services->set(WordTermMatcher::class)->tag('fd.symfony.log.viewer.term_matcher'); $services->set(LogRecordMatcher::class)->arg('$termMatchers', tagged_iterator('fd.symfony.log.viewer.term_matcher')); }; diff --git a/src/Service/Matcher/ChannelTermMatcher.php b/src/Service/Matcher/ChannelTermMatcher.php new file mode 100644 index 00000000..fbec2288 --- /dev/null +++ b/src/Service/Matcher/ChannelTermMatcher.php @@ -0,0 +1,30 @@ + + */ +class ChannelTermMatcher implements TermMatcherInterface +{ + public function supports(TermInterface $term): bool + { + return $term instanceof ChannelTerm; + } + + public function matches(TermInterface $term, LogRecord $record): bool + { + foreach ($term->channels as $channel) { + if (strcasecmp($channel, $record->channel) === 0) { + return true; + } + } + + return false; + } +} diff --git a/src/Service/Matcher/SeverityTermMatcher.php b/src/Service/Matcher/SeverityTermMatcher.php new file mode 100644 index 00000000..cd3b2896 --- /dev/null +++ b/src/Service/Matcher/SeverityTermMatcher.php @@ -0,0 +1,30 @@ + + */ +class SeverityTermMatcher implements TermMatcherInterface +{ + public function supports(TermInterface $term): bool + { + return $term instanceof SeverityTerm; + } + + public function matches(TermInterface $term, LogRecord $record): bool + { + foreach ($term->severities as $severity) { + if (strcasecmp($severity, $record->severity) === 0) { + return true; + } + } + + return false; + } +} diff --git a/src/Service/Parser/ExpressionParser.php b/src/Service/Parser/ExpressionParser.php index 0885211d..9e3b10c7 100644 --- a/src/Service/Parser/ExpressionParser.php +++ b/src/Service/Parser/ExpressionParser.php @@ -9,8 +9,11 @@ /** * BNF: * ::= | - * ::= - * ::= before: | after: + * ::= | | | + * ::= before: | af + * ::= severity: + * ::= channel: + * ::= exclude: * ::= "" | '' | */ class ExpressionParser diff --git a/src/Service/Parser/TermParser.php b/src/Service/Parser/TermParser.php index 52ed8f1e..1d830700 100644 --- a/src/Service/Parser/TermParser.php +++ b/src/Service/Parser/TermParser.php @@ -3,9 +3,10 @@ namespace FD\LogViewer\Service\Parser; -use Exception; +use FD\LogViewer\Entity\Expression\ChannelTerm; use FD\LogViewer\Entity\Expression\DateAfterTerm; use FD\LogViewer\Entity\Expression\DateBeforeTerm; +use FD\LogViewer\Entity\Expression\SeverityTerm; use FD\LogViewer\Entity\Expression\TermInterface; use FD\LogViewer\Entity\Expression\WordTerm; use FD\LogViewer\Reader\String\StringReader; @@ -37,6 +38,14 @@ public function parse(StringReader $string): TermInterface return new DateAfterTerm($this->dateParser->toDateTimeImmutable($this->stringParser->parse($string))); } + if ($string->read('severity:') || $string->read('s:')) { + return new SeverityTerm(array_map('trim', explode('|', $this->stringParser->parse($string)))); + } + + if ($string->read('channel:') || $string->read('c:')) { + return new ChannelTerm(array_map('trim', explode('|', $this->stringParser->parse($string)))); + } + if ($string->read('exclude:') || $string->read('-:')) { return new WordTerm($this->stringParser->parse($string), WordTerm::TYPE_EXCLUDE); } From 0b789ae6c5a76d58d38203e36cd87148aa9200ec Mon Sep 17 00:00:00 2001 From: Frank Dekker Date: Sat, 27 Jan 2024 22:42:02 +0100 Subject: [PATCH 02/14] Remove level and channel from log record output --- frontend/src/models/LogRecords.ts | 8 -------- frontend/src/stores/log_records.ts | 13 ++----------- frontend/src/views/LogView.vue | 18 +----------------- src/Entity/Output/LogRecordsOutput.php | 12 ++---------- src/Service/File/LogRecordsOutputProvider.php | 1 - 5 files changed, 5 insertions(+), 47 deletions(-) diff --git a/frontend/src/models/LogRecords.ts b/frontend/src/models/LogRecords.ts index 39d9c547..c940bbb5 100644 --- a/frontend/src/models/LogRecords.ts +++ b/frontend/src/models/LogRecords.ts @@ -3,14 +3,6 @@ import type Paginator from '@/models/Paginator'; import type Performance from '@/models/Performance'; export default interface LogRecords { - levels: { - choices: {[key: string]: string}; - selected: string[]; - }; - channels: { - choices: {[key: string]: string}; - selected: string[]; - }; logs: LogRecord[]; paginator: Paginator | null; performance?: Performance; diff --git a/frontend/src/stores/log_records.ts b/frontend/src/stores/log_records.ts index 10251bf3..2e7ff9ca 100644 --- a/frontend/src/stores/log_records.ts +++ b/frontend/src/stores/log_records.ts @@ -5,8 +5,6 @@ import {ref} from 'vue' export const useLogRecordStore = defineStore('log_records', () => { const defaultData: LogRecords = { - levels: {choices: {}, selected: []}, - channels: {choices: {}, selected: []}, logs: [], paginator: null }; @@ -14,20 +12,13 @@ export const useLogRecordStore = defineStore('log_records', () => { const loading = ref(false); const records = ref(defaultData); - async function fetch(file: string, levels: string[], channels: string[], direction: string, perPage: string, query: string, offset: number) { + async function fetch(file: string, direction: string, perPage: string, query: string, offset: number) { const params: { [key: string]: string } = {file, direction, per_page: perPage}; if (query !== '') { params.query = query; } - const levelChoices = Object.keys(records.value.levels.choices); - if (levels.length > 0 && levels.length !== levelChoices.length) { - params.levels = levels.join(','); - } - const channelChoices = Object.keys(records.value.channels.choices); - if (channels.length > 0 && channels.length !== channelChoices.length) { - params.channels = channels.join(','); - } + if (offset > 0) { params.offset = offset.toString(); } diff --git a/frontend/src/views/LogView.vue b/frontend/src/views/LogView.vue index ade05f81..3952d881 100644 --- a/frontend/src/views/LogView.vue +++ b/frontend/src/views/LogView.vue @@ -1,9 +1,6 @@