Capture the last time code (for a given event type) in a log file

Ain’t that the truth. The epiphanies, normally, happen when in the shower or simply away from the Mac.

1 Like

Mhm, seems like a macro can aways be improved, rebuilt or tidied up better!
I also have these shower epiphanies, haha

1 Like

Regular expressions are extremely powerful and cool but they are often best used in combination with other tools (like with tail here). You could probably engineer a regex that would do what you need, using some of the more advanced features of regex syntax, but it would almost certainly be going the long way around. (If you’re curious, search for “negative lookahead” in a regex manual.)

By the way, one good way to learn regex on a Mac is to install the free version of the text editor app BBEdit. The manual’s chapter on grep search is a very well-written regex tutorial, and the app has lots of helpful features for designing and testing your regular expressions.

1 Like

Very often, the best way to do that is not to use regular expressions. They don't serve well as a default approach.

Trying to solve a problem by using a regular expression often adds additional problems and costs time – not really an advantage at all ...

Your experience is common:

have now spent the better part of the evening trying to figuring out ... (a regex issue rather than the problem itself)

The underlying problem here seems to be something closer to:

Capture the last time code in a log file

and that might have served you better as a thread title – harvesting various ways of solving the problem itself, which appears to be that of:

  • Obtaining the last non-blank line in a log,
  • taking the first 19 characters from that line,
  • and, possibly, converting those characters a (non string) computable date value of some kind.
1 Like

which does not describe the problem.

Better would be:

Capture the last time code in a log file that a specific event type occurred

for which your suggested approach would need to be modified.

2 Likes

Thanks.

So perhaps, for example:

  • Reversing the lines,
  • filtering the reversed lines for those containing a given event name,
  • and taking the first N chars of the first line yielded by that filter.

(where one and two above could be reversed)

1 Like

If you wanted to experiment with native KM actions ( bypassing both regular expressions and shell scripts ) you could, for example, try things like this:

Last time code in log file for given event type.kmmacros (6.8 KB)

1 Like

I am definitely interested in this experiment! As I don’t really know coding it would almost always be my intuitive goal to solve any problem within the native KM actions!

But if I was to use the timecode for a time difference calculation I would still need to load the elements of the TC into separate variables (Y1, M1, D1, H1, Min1, Sec1 (to use a Time()-calculation)), right? For something Regex captures seems like the maybe best tool? (The original full task I set out to solve was to calculate the time difference between the last time the app was quit before being stated up again.)

Thank you for this explanation! Very useful to know that Regex is often best used in combination with other tools, and that it is not necessarily the do-it-all-tool for these kinds of tasks as I thought it would be.
Thank you also for pointing me in the direction of how I could best learn the tool better!

1 Like

One of the good things about using a Keyboard Maestro native action to do this is that it is very clear to see what is going on, especially if the Macro doesn't work as expected or you want to edit at a future date. To get the value for the hour in this case is simple as the positions of those digits will be the same so you can use the same technique @ComplexPoint has shown. Also, you can rename a Keyboard Maestro Action, in effect adding in a note of what that Action is doing.

3 Likes

This solution makes allot of sense!
Only thing is that I have this (mis)conception that more separate KM-actions equates to a more processor taxing more time consuming macro. But I guess there’s no real difference between dividing it up into separate steps like this or not

Consuming your time, or the machine's ?

(Run-time differences will be very small, whereas all the "I have spent the better part of the evening trying to figure out" time is far from insignificant)

I was thinking about the machine’s time.
I am really slow at building macros so my time is anyways flying away, haha!

Well, if you want to have hours, minutes, seconds, frames saved to separate variables you are going to have to do some form of processing whatever the method. We’re not talking about processing vast amounts of data here - just some lines of text. So, my guess is the method won’t make any noticeable difference to your overall task. I suppose try it and see.

I guess this also.
I always have this idea that I should make the macro as short/simple, i.e. as few steps/actions, as possible. But it makes good sense not always getting too caught up in this idea!

Yes, that is a good aim. One of the great things about Keyboard Maestro is that once you have a Macro that works and does what you want, if you find a better way at a future date to do some part of it you can always make a new version to use that method instead.

Also, if you have a series of Actions that essentially do one task you can multiple select them, Engroup them in a Group Action, rename that Group to something that explains the task and then collapse the Group so you don't have to view all the separate Actions.

Actions>Engroup>Group

1 Like

This simple regex will do the trick:
image

2 Likes

Thank you! The (?m) and the (?s:.*) is doing some magic here I do not understand yet, but it’s working!

In the interest of learning regex slightly better I am fiddling a little with this approach now. By moving the last parenticis before App Starting I am able to capture only the timecode part of the line:

(?m)(?s:.*)(^.+)App Starting

But am I right in thinking that I'd have to run a separate action here to capture the individual datetime elements into separate variables to run a Time()-calculation? (Using (\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+) like the Macro Image below shows.) Or could it be possible doing this all in one line of regex?

The (?m) works with the ^ to indicate the input variable consists of multiple lines and to start matching at the beginning of each separate line instead of the entire string.

The (?s:.*) gets the last match.

You can match each date component separately in one regex. See screenshot.
image

1 Like

Thank you so much for this explanation! And wow, this amazing do-it-all line of regex!

This is exactly what I was setting out in hopes to find when first creating this thread, and it's amazing to now see it actually existing and working.

As a wonderful bonus this thread have given me other angles to tackle this problem from, and through this I've gained important further insights into KM as a whole. Thank you all so much for this!

1 Like