Check the last time a specific macro ran

I could achieve this by creating a global macro that gets updated when the main macro runs, for example I could have a "Last Time X Macro Ran" global variable and it would update at the end of the macro via an action to change the old date to the current date, then when I want to know when it ran, I just grab the value from that variable.

But is there a way to do this without using a global variable?

Yes - just look in the KM Engine log file which records when every macro is run - as well as a load of other stuff.

KM > Help > Open Logs Folder then open the Engine.log file.

Or just use one of the numerous macro available to show the info, like

Sorry, I should've been more specific. I don't want to just "know" that information, I want to use it in a macro. I use the Engine log a lot when there's an error, but in this case I need that info available to use in a macro. I don't think that can be done, right?

EDIT: @thoffman666 reminded me that the log is actually a file that I can then search inside using RegEx.

I saw this post as well, but this grabs a list of all macros and I just need a specific macro. I'm sure that macro is customizable to do that, but I don't really understand any of that javascript being used... that's way too complex for me.

It's possible to search the log file with a customized regex to extract the time information for a specific macro, and load that extracted information into a variable. The variable could then be used in a macro in any way you like. Just choose File as your source in the Search action.

1 Like

Oh I see what you mean.
So I would search here, right?

I forgot that this is actually a file that can be accessed.
One thing I'm missing in the log file is the UUID, because if I change the name of the macro, then it won't work anymore. Do you know if there's a way to check that info in the log file? I see the date and the name, but not the UUID

I was assuming that the log included UUID, but I guess not. In that case, I guess you would have to search by name and remember not to change the name (or remember to change the regex to the new name).

I rarely change the names, to be honest, but it could happen (sometime it does).
I think that in this case, relying on a global variable would be safer.
The main macro can have an action at the end that sets the date and then when I run the second macro, it checks that variable. That way I don't have to worry about the name.

But thanks for reminding me about the log being an actual file that I can access.

1 Like

Another possibility is the Log action:

In the log file, that generates the info you want:

2024-02-06 06:59:48 Log: 40C8B546-6123-4B3D-B2DE-9B2AF9C747A1 ended at 6:59:48 AM

This wouldn't require setting up and updating a global variable; you could just add the log call to any macro whose end-run time was needed in another macro, then grab the value from the log. You'd have to make sure you only grabbed the last one, of course, which would be a little tricky but not too hard (he says without actually trying to build such a thing).



And you could skip the log step by simply setting a variable to that same text.

1 Like

Ok, that makes sense. Since I will have that UUID and the time, I can filter that by using RegEx and just get the date. Getting closer...

He asked about doing it without a global variable, hence my Log suggestion—my assumption was that he may want to do this for numerous macros, and doesn't want a number of global variables hanging around?

Anyway, to extract the latest entry for a given macro, you'd just use a Shell Script action with this:

grep "UUID-of-macro-goes-here "/Users/your_user/Library/Logs/Keyboard Maestro/Engine.log" | tail -n 1

But yes, if you're willing to use global variables, that'd save some steps.


I'm now testing these options and there's an issue: that will give me the date that the macro ran, but since I need to run the macro to get that value, it will not give me the latest date, it will give me the current date (because I'm running it now).

For example if the macro ran yesterday and I run it today to get that information using the proposed solutions, I'm getting the today's date, not yesterday's.
At least when I tried it now, that's what I got.

I'm not sure I fully understand the issue: The solution I proposed will record the last time the macro was run. I assumed you needed to use that in another macro…are you trying to use that value in the same macro?


Maybe some context will help:

I'm building a quick and easy backup system that I can quickly run when I make important changes to some files. I use Carbon Copy Cloner for bigger backups, but that's not always a fast solution and since I sometimes need to use all my USB ports while I work, disconnecting some to then connect the backup disk and wait for it to backup, is not always ideal.

So I'm building a macro that will find files modified in the last X minutes and will copy those files to both iCloud and a secondary internal disk, just in case the main disk dies/fails for some reason, while I'm working. Then once I'm done and I can disconnect my USB devices and I don't have to be there waiting for it to finish, I use CCC to create a real backup.

So if I run the macro at 10:30am for the first time and then I want to run it at 11:45, I want to set the "modified date" to 1:15 so it will find all modified files in that period of time.

So the macro would be something like this:
Action: check when THIS macro ran and set that to a value in minutes and save it as Local__Minutes
Action: grab the list of files using shell find "/Users/dannywyatt/My Files" -type f -mmin -"$KMVAR_Local__Minutes"

Then it would run the other actions

Context is always helpful :).

That is a very different request than recording the last time a macro ran, so the solutions proposed here won't really help you very much, as they simply record the time a given macro ran, but know nothing of the delta time between the last two runs.

Can you explain why it's important to be able to specify the macro via UUID? This sounds like it's just one macro that's running, right? Your backup system macro, and you just want to know the interval between the last time it ran and the current run. Is that right?


Yes, sometimes I forget that I have the whole picture in my mind, but other people don't... :wink: sorry about that.

But this seems to just give me the current date, because if that log action is in the macro itself, it will give me the current date, not the date before this run (for example 30 minutes ago). You know what I mean?

By setting the current date as a local variable, and the last date as another local variable, I could then calculate the difference and that number would set the minutes I need to set.

This is just to avoid the issue of me renaming the macro.

In theory, yes, but because I'm working and I use shortcuts that are linked to some macros etc, I could have other macros running as well.

Yes, correct.
I mean, as I said, if this is too complex, I can add an action at the end of the macro to just set the date as a global macro. I like to avoid having too many global macros, if possible, but when it's easier and faster, so be it. No big deal. I was just wondering if there was a simpler way. Maybe not.

Still related to this macro, but a bit off topic:
I need to exclude certain paths from the search.
I found that I can do that by using prune like this:
find . -path ./dir1 -prune

How would I add more paths? Would I just add the paths after the first one, before -prune? Like this:
find . -path ./dir1 ./dir2 ./dir3 -prune

Source here

You can use Prepend Text to Variable to add the current date as a line of text before the previous date. You can either write that to a txt document or keep it as a variable. In either case, you can continue to prepend (retaining a list of all modification dates), or use logic to keep it trimmed it to that last two dates. Using the last two dates allows you to calculate the time span.

Yes, using a global variable was my first workaround, but I wanted to know if there was an internal way of doing it maybe via a token or something, that didn't rely on a global variable or, as you suggested, an external file.

But it seems there's no other way and I will have to rely on the global variable. No problem :slight_smile:
I appreciate the help and suggestions

If the reason you don't like accumulating variables is to keep the list shorter, then write the information to a text file instead. I do this all the time, especially because writing text files to Dropbox allows me to use the information across all devices.