FYI,
Thanks William for the consult.
The use case is a particular log that is kept in a lot of appliances I manage &
they can get out of hand. Thankfully the log utility that I use to fetch them
has a 'WHERE begintime > ...' option. After the script that uses this snippet
passes through, I get real DateTimes from each record, & stash the latest for
each node. For the next run, I read the DateTimes and ask only for records
that are newer. That particular script monitors ((6 x 8) + (2 x 14)) of these
spastic logs. Raku made short work of it (and thank you Promises...). Concise
reports every morning now, delivered in seconds.
My solution for the question I posed in the mailing list:
#!/usr/bin/env raku
my $data = q:to/END/;
3_1 2025-08-30T03:06:44-04:00 info Advanced Intrusion
Detection Environment (AIDE) detected potential changes to software on this
system. The changes are listed in /var/log/aide/aide.log and also at the end of
this alert message.
Summary : :
Total number of entries :
54096
Added entries : 1
Removed entries : 0
Changed entries : 0
1_1 2025-08-14T07:18:41-04:00 critical After initial accelerated
space reclamation, file system / is 80% full, which is equal to or above the
80% threshold. Accelerated space reclamation will continue.
This alert will be cleared
when file system / becomes less than 75% full.
Top three directories
ordered by total space usage are as follows:
/opt : 2.69G
/root : 2.15G
/usr : 1.76G
1_2 2025-08-14T17:36:40-04:00 clear File system / is 58% full,
which is below the 75% threshold. Normal space reclamation will resume.
END
my grammar EXADATALOG-grammar {
token TOP { <log-record>+
}
token log-record { <log-record-start> || <log-record-continue>
}
token log-record-start { ^^ <log-record-herald> \s+ <log-text>
}
token log-record-herald { \s* <name> \s+ <datetime> \s+ <status>
}
token log-record-continue { ^^ <!before <log-record-herald>> <log-text>
}
token name { \d+ '_' \d+
}
token datetime { \d\d\d\d '-' \d\d '-' \d\d 'T' \d\d ':' \d\d
':' \d\d '-' \d\d ':' \d\d }
token status { \w+
}
token log-text { .+? \n
}
}
class EXADATALOG-record {
has Str $.name is required;
has DateTime $.datetime is required;
has Str $.status is required;
has Str @.message;
}
my @EXADATALOG-records;
class EXADATALOG-actions {
method log-record-herald ($/) {
@EXADATALOG-records.push: EXADATALOG-record.new(
:name(~$/<name>),
:datetime(DateTime.new(~$/<datetime>)),
:status(~$/<status>),
);
}
method log-text ($/) {
@EXADATALOG-records[* - 1].message.push: ~$/.chomp;
}
}
EXADATALOG-grammar.parse($data, :actions(EXADATALOG-actions));
for @EXADATALOG-records -> $record {
printf "%-6s%-28s%-10s\n", $record.name, $record.datetime, $record.status;
printf "\t%s\n", $record.message.join("\n");
}
=finish
Mark
________________________________
From: William Michels <[email protected]>
Sent: Monday, October 27, 2025 11:32 AM
To: [email protected] <[email protected]>
Subject: Re: Grammar: "match anything that is not this thing"
Hi Mark,
You could try a Boolean condition-check:
https://stackoverflow.com/questions/64909029/is-it-possible-to-do-boolean-assertions-with-raku-regex<https://urldefense.proofpoint.com/v2/url?u=https-3A__stackoverflow.com_questions_64909029_is-2Dit-2Dpossible-2Dto-2Ddo-2Dboolean-2Dassertions-2Dwith-2Draku-2Dregex&d=DwMFaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=thT0VsM9yJlPPLROt23gXb6x82v5JicoCnxKT8v5YUo&m=ghZ4xkUVGPjDg8LDBOViDXYfnvxS-3xU7BNUSwYO6kvU5E87OgSJXY5KseI_nIT-&s=RYDHWVLmPaaMdNi46IpYmYqEC5jLTYLaa5ZQMk2LazI&e=>
https://docs.raku.org/language/regexes#Regex_Boolean_condition_check<https://urldefense.proofpoint.com/v2/url?u=https-3A__docs.raku.org_language_regexes-23Regex-5FBoolean-5Fcondition-5Fcheck&d=DwMFaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=thT0VsM9yJlPPLROt23gXb6x82v5JicoCnxKT8v5YUo&m=ghZ4xkUVGPjDg8LDBOViDXYfnvxS-3xU7BNUSwYO6kvU5E87OgSJXY5KseI_nIT-&s=RUUsdBOYb3_IgL5bwJt_Fr7a--4S6ZksnHFoL0K5v58&e=>
Darren Duncan had a similar question here on the mailing list, back in July
2023 (second like below is my reply):
https://www.nntp.perl.org/group/perl.perl6.users/2023/07/msg11016.html<https://urldefense.proofpoint.com/v2/url?u=https-3A__www.nntp.perl.org_group_perl.perl6.users_2023_07_msg11016.html&d=DwMFaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=thT0VsM9yJlPPLROt23gXb6x82v5JicoCnxKT8v5YUo&m=ghZ4xkUVGPjDg8LDBOViDXYfnvxS-3xU7BNUSwYO6kvU5E87OgSJXY5KseI_nIT-&s=YInPBYSJ0Xnu-HOFWejCXe1RIPqqIzyMmdlE-44rNh4&e=>
https://www.nntp.perl.org/group/perl.perl6.users/2023/07/msg11018.html<https://urldefense.proofpoint.com/v2/url?u=https-3A__www.nntp.perl.org_group_perl.perl6.users_2023_07_msg11018.html&d=DwMFaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=thT0VsM9yJlPPLROt23gXb6x82v5JicoCnxKT8v5YUo&m=ghZ4xkUVGPjDg8LDBOViDXYfnvxS-3xU7BNUSwYO6kvU5E87OgSJXY5KseI_nIT-&s=vcD_QMfhpF2rUeq_VpfiDxLVxvlslJOE5KZKide02Zo&e=>
HTH, Bill.
On Oct 26, 2025, at 12:35, Mark Devine <[email protected]> wrote:
The logic of the idea seems to be sound, but I see here that
<not-log-record-herald> matches “” (blank). I was hoping that
<not-log-record-herald> would consider the string a match and pack it in the
Match object. I’d use an action to accumulate if necessary. But since it
discards the string, I think I might be out of luck entirely. Thoughts?
TOP
> | log-record
>
| | log-record-herald
>
| | | name-field
>
| | | * MATCH "3_1"
>
| | | datetime-field
>
| | | * MATCH "2025-08-30T03:06:44-04:00"
>
| | | status-field
>
| | | * MATCH "info"
>
| | * MATCH " 3_1 2025-08-30T03:06:44-04:00 info"
>
| | message
>
| | | not-log-record-herald
>
| | | | log-record-herald
>
| | | | * FAIL
>
| | | * MATCH ""
Thanks,
Mark
From: Mark Devine <[email protected]>
Sent: Saturday, October 25, 2025 1:16 PM
To: [email protected]
Subject: Grammar: "match anything that is not this thing"
RE Gurus,
I have a “match anything that is not this thing” pattern that I haven’t worked
out yet.
Colorized below is the (log) data to parse, sometimes multi-line, sometimes
single line, in a repeated pattern. Here’s my test script:
#!/usr/bin/env raku
use Data::Dump::Tree;
use Grammar::Debugger;
my $data = q:to/END/;
3_1 2025-08-30T03:06:44-04:00 info Advanced Intrusion
Detection Environment (AIDE) detected potential changes to software on this
system. The changes are listed in /var/log/aide/aide.log and also at the end of
this alert message.
Summary : :
Total number of entries :
54096
Added entries : 1
Removed entries : 0
Changed entries : 0
1_1 2025-08-14T07:18:41-04:00 critical After initial accelerated
space reclamation, file system / is 80% full, which is equal to or above the
80% threshold. Accelerated space reclamation will continue.
This alert will be cleared
when file system / becomes less than 75% full.
Top three directories
ordered by total space usage are as follows:
/opt : 2.69G
/root : 2.15G
/usr : 1.76G
1_2 2025-08-14T17:36:40-04:00 clear File system / is 58% full,
which is below the 75% threshold. Normal space reclamation will resume.
END
my grammar EXADATALOG-grammar {
token TOP { <log-record>+
}
token log-record { <log-record-herald> \s+ <message>
}
token log-record-herald { ^ \s+ <name-field> \s+ <datetime-field> \s+
<status-field> }
token name-field { \d+ '_' \d+
}
token datetime-field { \d\d\d\d '-' \d\d '-' \d\d 'T' \d\d ':' \d\d
':' \d\d '-' \d\d ':' \d\d }
token status-field { \w+
}
token not-log-record-herald { <!log-record-herald>
}
token message { <not-log-record-herald>+
}
}
ddt EXADATALOG-grammar.parse($data);
=finish
My strategy is to characterize the start of each record with
<log-record-herald> as the anchor for the logic. Match a <log-record-herald>
and match a potentially multi-line <message>, with <message> being anything
that IS NOT a<log-record-herald>.
Is this a viable approach? Anyone know what I’m missing here?
Thanks,
Mark