top of page

iOS Unified Logs - log command major updates not to miss!

  • Photo du rédacteur: Lionel Notari
    Lionel Notari
  • 7 juin
  • 9 min de lecture

Dernière mise à jour : 31 août

I recently updated my Mac Mini to macOS 15.5 and decided to take a closer look at what’s new with the log collect command. If you’re working with iOS Unified logs or if you’ve been following my posts and forensic tools, you’ve probably used, or at least seen, the log command many times before. For example, the log collect command lets us extract logs from an Apple device. This is the same command (with a few extra options) that’s used in my forensic acquisition tool. Similarly, my parsing tool uses log show and log stats. These commands are now pretty well known in the world of iOS log analysis.

So imagine my surprise when I noticed a new log option! Yep, a brand-new one. That doesn’t happen often, and I’ll come back to that later in this post. That’s not the only new thing, though: there’s now a new way to filter logs when using log collect, and a small but super useful update to log stats! I’ve actually been waiting for that one for a while.This new option required an update to my tool, so version 2 is available at the end of this article!


To sum it up, here’s what I want to share with you today:

  • a new option for the log command,

  • an updated filtering method for log collect,

  • and a nice improvement to log stats!


iOS Unified Log - THE new command!

To get all the options for the log command, we can simply type the following command in our Mac Terminal: log help. It’s as simple as that. Now, let’s take a step back. In previous versions of macOS, we would get the following commands:

ree

No surprises here, I’ve talked about these commands many times before. But when I ran the same command on macOS 15.5, I got the following result:

ree

Did you spot the difference? log repack!! That’s really cool and this our new log command! It lets us build a new log archive from an existing one! According to the documentation, it’s described as: "Repack all logs in a logarchive matching a predicate into a new logarchive with only the matching logs."


Thank you, Apple, finally! Well, now that we can send logs to a database, it’s not necessarily the most useful feature, but it’s definitely worth testing out. I would have loved to have this feature a few years ago when I had to send my relevant in a text file ....


First, let’s take a look at the options specific to this command:

ree

I’m not gonna lie, I’m pretty disappointed! The options available for this command are really limited right now. While we can use --predicate to filter logs, it’s not possible to limit the date range with --start and --end, like we can with the log show command, for example:

ree

It's pretty clear how much more precise log show is, offering a lot more options for filtering logs. In this context, the new command is nice and definitely worth testing, but I think Apple will need to update it. If we have a full archive from which we want to extract logs, we basically have two options:


  1. Stick with log show and send the output either to a file or, for example, to a JSON file. Right now, tools that convert logarchive files into databases use this method. log show is very effective because it allows us to set a start and end date to limit the export size. All of these steps are automated, for example, in my parsing tool.


  1. Use repack to create a filtered log archive from the original log archive. However, I think there are a few issues here:


  • You need to be comfortable with predicate commands to extract exactly the logs you want.


  • The output file will again be a log archive... so you won’t be able to migrate it to Windows, for example, and a tool to convert it into a database will be necessary.


  • While the conversion from logarchive to a database might be faster, don’t forget that using the terminal with multiple "predicate" parameters can be really slow! So, it's not guaranteed that this will save us time in our analysis.


This also adds an extra step of transition. From a forensic perspective, we’ll need to ensure we can clearly link this newly filtered log archive to the original full log archive, which, in turn, must be linked to the original iPhone. I see major risks here in terms of evidence continuity.


-> For all these reasons, in my opinion, we should be cautious with this command. However, I’m really eager to test it out and do some comparisons! For that, I have a full log archive from my phone, and we’ll make the comparisons as follows:


  • I will run a log stats --predicate "...." command on the full log archive to get precise log statistics.


  • Then, I’ll use the log repack --predicate "..." command with the same predicate as above to generate a filtered log archive.


  • Next, I’ll generate new statistics with log stats on this filtered logarchive. I should get the same results as in step 1.


To start, I’ve decided to work with the following: apsd: Screen did unlock (Was locked for 305.244956 seconds). I really like this log. So, the predicate command I’ll be using is: process=="apsd" && composedMessage contains "Screen did unlock".


Here are the statistics of this predicate command:

ree

So, we’re expecting a total of 5 logs! Let’s see what we get with log repack and log show.


How does log repack exactly work?

Well, the command simply creates a complete copy of the log archive you want to repack, and then it starts filtering. You’ll see a log archive named "name_repacked.logarchive", and the size will shrink as the parsing goes on:

ree

Finally, the output I had in the Terminal made me believe something went wrong!

ree

Despite numerous tests, I couldn’t get any other results than this error message! It was a log archive from an iPhone running iOS 18.4, extracted just a few minutes before the repack. But when I open the logarchive in Console, I do see the expected number of logs: 5, as expected:

ree

So it’s not a very serious issue, and honestly, I doubt there’s much we can really do about it. To go further, we can see that we get the same number of logs with the log show command and this one doesn’t generate any errors!

ree

However, the statistics from this new logarchive are very interesting!

ree

There are indeed 5 logs as expected, but a total of 45 events, and, of course, we have no information about the 40 events that are not logs! Any idea what they could be?


They are timesyncEvents! I documented that these events don’t appear in the statistics, which was quite confusing. That was in this article! I have no idea why these events are included in my repacked logarchive…


I parsed this repacked logarchive with my tool, and the forensic report clearly confirms that these are timesyncEvents!

ree



Finally, be aware that the “repacked” logarchive is very large, over 150 MB for just 5 logs! Although the results match, log show remains faster and lighter! It’s a new feature worth knowing, but given the drawbacks mentioned earlier, I prefer to stick with log show. Let me know if you manage to obtain a better result than me!



iOS Unified Logs - log collect update

The log collect command also got an update! While it’s still not possible to set an --end option to limit log extraction, which is surprising (to say the least), especially since we can set --start, there is now the ability to use predicates to export only certain logs into a log archive!

ree

However, once again, I’m not sure this will be very useful. Indeed, exporting logs into a log archive isn’t the part that takes the most time, and although a log archive with fewer logs will be faster to convert into a database, it does require knowing quite a bit about predicate commands. From experience, the more predicates you add to your log command, the longer it takes.


Additionally, we know that logs are only stored in memory for a short period of time (I wrote a detailed article on the timeToTive of Unified logs, which you can find here)... So, what happens if you realize a few days or a few weeks after the acquisition that you haven’t extracted all the logs you needed? It’s too late...


So, it sounds like a false good idea! It’s great to see that Apple is continuing to develop this command and add improvements, but for now, I’ll stick with exporting all the logs into a log archive. It's much safer ! I don’t see any good reason to limit the log acquisition, whether by setting a start date or using a predicate during the extraction.


iOS Unified Logs - log stats update

Finally, we got a major update for the log stats command! Not that it’s revolutionary, but I’ve been waiting for this one for a long time! We can now use the --end option with the log stats command, just like we can with log show! And that, changes everything! For me, it's a game changer.

ree

Indeed, previously, we could use the log show command with the --start and --end options to define a date range of interest, thus limiting the number of logs exported. This is exactly what I use in my tool.

ree

Logs corresponding to the date range are then sent to the final database. From a forensic perspective, it seems crucial to compare what we have in the database with the original log archive to ensure that the script hasn’t altered anything and to avoid any blind spots. The more documented the process is, the better.


However, it was previously impossible for me to generate statistics for the log archive using log stats on a date range, since the --end option wasn’t available. In other words, it was impossible to confirm that what was in the database exactly matched what was in the log archive. I didn’t like that at all and therefore didn’t recommend using a date range with log show. That’s all ancient history now, and that’s fantastic news!


It will now be possible to use log show with --start and --end to define a date range of interest, speeding up the conversion of the log archive into a database, and then generate an accurate comparison between the database and the log archive! If the other two new commands presented in this article didn’t convince me much, this one is a real game-changer for me and will drastically speed up our investigations without any limitations!


Let’s take an example!

In the first version of the script, using a date range for log parsing would generate the following sentence at the very top of the forensic report:

ree

This warning was meant to alert the investigator that the log archive statistics might not match those of the database when a date range was used! If you'd like to learn more about this, feel free to check out this article:

All of that is now a thing of the past. My tool has been updated, and version 2 will include this new option to speed up the conversion process, filtering, and therefore your investigations. . So, let’s take a look at an example using the following date range on my extraction:

ree

Good news, the statistics match! Let’s take a closer look at all of this!


Database

ree

Logarchive:

ree

We can see that we have the same start and end dates (blue rectangle), from 17.05.2025 19:00:00 to 19:59:59, with a total of 814,080 events (yellow oval) in both cases, so that’s perfect!

We also notice that the number of logs (678,062), signposts (25,792), stateEvent/statedump (428), and activityCreateEvent (109,779) is exactly the same between the log archive and the database.


As a reminder, the number of "Default" events also matches, you just need to subtract the number of signpost events from the log archive stats: 636,704 - 25,792 = 610,912.

This is a well-known and documented inconsistency on macOS, explained in the following article: https://www.ios-unifiedlogs.com/post/ios-unified-logs-the-myth-of-30days-retention


To go even further, we can also analyze the logs by process:


Database


ree


Logarchive:

ree

Once again, the results are perfect and consistent between the logarchive and the database! The script is accurate and this new option added to the log stats command will definitely speed up our unified log analysis, that’s such a great news! There’s now nothing stopping us from selecting a specific date range during analysis. In just a few minutes, it’s now possible to generate a database containing only the relevant logs for a chosen time period. With these improvements of the log stats command that will speed up the conversion and parsing process, I recommend never limiting the acquisition of unified logs by setting a start date. Always extract all logs from the device of interest!


If you’re wondering why there’s a slight mismatch with the “kernel” and “SpringBoard” processes, it’s due to lossEvents. I’ve analyzed and explained this in detail in this article. Fortunately, this is not caused by the tool itself!


My parsing has been updated to version 2!

This version includes the new log stats option, so I highly recommend downloading it here and giving it a try, I would be glad to hear your feedback! Unified log investigation has never been this fast. A compatibility check is built into the tool, so it still works on previous macOS versions that don’t support the log stats --end option. In that case, the warning message will be printed at the top of the report like in version 1.


I also slightly changed the method for selecting the logarchive ro resolve a few issues, it’s now possible to enter the full path directly:

ree


When the path and the logarchive are valid, a small checkmark appears on the right!


Regarding the start and end Dates/Time:


  • You can enter them manually (without using the calendar) in the following format: yyyy-mm-dd HH:MM:SS. Time is optional, you can also enter a date only:

ree

In the example above, the extraction goes from the first log on May 16, 2025, to the last log on May 17, 2025:

ree




Enjoy your Digital investigations ! Lionel Notari










© 2023 - 2024 by Lionel Notari - All Rights Reserved

bottom of page