Monitoring macOS

Configuration

Configure Collectord on a Mac: the configuration files, the managed preferences a configuration profile sets, the fleet label and hardware class, the inputs, and the shipped defaults.

Change what Collectord collects on a Mac and where it sends it, by hand on one Mac or for a whole fleet. This page covers the configuration layers, the managed preferences a configuration profile sets, the inputs, and the shipped defaults.

Collectord reads its settings from the configuration files in /opt/collectorformacos/etc, and from a configuration profile when your MDM deploys one. Each layer overrides the one before it:

  1. 001-general.conf holds the defaults, shown in full below. An upgrade replaces it, so don’t edit it.
  2. 002-user.conf holds your settings (mode 600). The package creates it when it is missing, with the license and the HEC URL and token to fill in, and the metrics index named. An upgrade keeps it. Its keys override the defaults, even when you leave them empty.
  3. Environment variables, in the form COLLECTOR__<ANYNAME>=<section>__<key>=<value>: for example, COLLECTOR__LOGLEVEL=general__logLevel=debug. launchd passes the LaunchDaemon none of its own, so they matter only when you run collectord by hand.
  4. A configuration profile for the com.outcoldsolutions.collectord domain: the managed preferences. A fleet’s profile has the last word.

To override a default, copy its section header and the key into 002-user.conf:

002-user.conf ini
1[input.macos_crash_reports]
2userDirectories = false

Apply a change

Collectord checks its configuration files and the profile for a change every 10 seconds. A reload applies a new license and a new log level. Everything else applies at the next start: the Splunk URL and token, the indexes, the log packs, the inputs. Restart Collectord after you change them:

bash
1sudo launchctl kickstart -k system/com.outcoldsolutions.collectord

A SIGHUP reloads at once instead of within 10 seconds. Collectord’s pid is the first line of /opt/collectorformacos/var/collectord/collectord.pid.

Fleet label, hardware class and host name

Every record and event carries two fields the dashboards, the Alert Catalog and your own searches filter by:

  • The fleet label. Set it with [general] fields.macos_cluster, or the FleetLabel managed preference; it is - when you set none. Give each group of Macs its own: ci, build-farm, laptops. In the events index the field is macos_cluster; in the metrics index, the dimension macos.cluster.
  • The hardware class. Set it with [general.macos] hardwareClass, or the HardwareClass managed preference, to auto, laptop, desktop or rack. Under auto, the default, a Mac with a battery is a laptop and any other a desktop. Nothing on a Mac tells a racked Mac mini from one on a desk, so set rack on the Macs in your racks yourself.

The Fleet Overview splits the fleet by hardware class. The Alert Catalog’s “Collectord stopped reporting” and “Network interface lost its link” templates leave laptops out by default, since a laptop goes quiet every time its lid closes.

The host of every record and event is the Mac’s name. That is the HostName an administrator set with scutil --set HostName, else its local host name (System Settings › General › Sharing), which stays the same from network to network. Set [general] hostname to name it yourself.

The license counts a Mac by its hardware UUID, so renaming a Mac does not make it a new one.

Managed preferences

A configuration profile for the com.outcoldsolutions.collectord domain configures a fleet without touching 002-user.conf on any Mac. Installation has the profile template and how to deploy it. Every key is optional, and each sets configuration keys after the files and the environment:

KeyTypeSets
AcceptLicenseboolean[general] acceptLicense
Licensestring[general] license
SplunkURLstring[output.splunk] url. It replaces every urls.<n> and ackUrls.<n> the files name, and moves an ackUrl to its host
SplunkTokenstring[output.splunk] token
SplunkInsecureboolean[output.splunk] insecure
EventsIndexstringthe index of every events input: [input.macos_logs], [input.macos_events], [input.macos_crash_reports], [input.macos_connections], [input.macos_apps] and each [input.files::<name>]
MetricsIndexstring[output.splunk] defaultMetricsIndex, the metrics index every stat goes to
FleetLabelstring[general] fields.macos_cluster
HardwareClassstring[general.macos] hardwareClass
LogPacksarray of stringsthe log packs turned on: every [input.macos_logs::<pack>] it names is on, every other one off
LogCountsOnlyboolean[input.macos_logs] countsOnly: count the unified log’s entries instead of forwarding them
ProcessStatsbooleanfalse turns [input.macos_processes] off: no process records and no busy-process events
Connectionsbooleanfalse turns [input.macos_connections] off
Appsbooleanfalse turns [input.macos_apps] off: no application inventory
LogLevelstring[general] logLevel

collectord verify lists each key the profile set and what it set, never the value. It also reports what it skipped:

  • A key of the wrong type is skipped and marked FAILED, and so is a LogPacks name no pack has.
  • A key Collectord does not know is listed and ignored.
  • A profile it cannot read applies nothing, and is marked FAILED with why.

macOS writes the profile to /Library/Managed Preferences/com.outcoldsolutions.collectord.plist, which every user of the Mac can read. So any local user can read a SplunkToken delivered this way. Give that token the macOS indexes only, or leave it out of the profile and deliver it in 002-user.conf.

Inputs

Every stats input sends to the metrics index (see Metrics index), and every other input sends events. To turn one off, set disabled = true in its section (disabled.host = true for the host record):

SectionWhat it sendsSource type
[input.system_stats]the host record: CPU, memory and memory pressure, swap, paging, load, uptime, the Mac’s model, chip, macOS version and serial numbermacos_stats_host
[input.macos_stats]CPU per core and cluster with the frequencies, GPU, power, thermals, fans, disks, filesystems, network interfacesmacos_stats
[input.macos_processes]the top executables by CPU and by memory, and each virtual machinemacos_proc_stats
[input.macos_status]security posture, pending updates, battery and power state, who is logged in, launchd services, Xcode, compliance resultsmacos_status
[input.macos_log_counts]the counts of the unified log’s entries, and the noise sampler’s rankingmacos_log_counts
[input.collectord_metrics]Collectord’s own metricsmacos_prometheus
[input.macos_logs]unified log entries of the enabled log packs, and the noise sampler’s sample messagesmacos_logs, macos_log_samples
[input.macos_events]host events: boots, sleep and wake, pressure, power and network changes, logins, setting and account changes, the inventory; and launchd service transitionsmacos_host_events, macos_launchd
[input.macos_crash_reports]a summary of every crash, hang, jetsam and kernel panic reportmacos_crash_report
[input.macos_connections]TCP and UDP connections by process and remote address, and the listening socketsmacos_connections
[input.macos_apps]the installed applications, and the installs, updates and removalsmacos_apps
[input.files::install_log]/var/log/install.logmacos_install_log
[input.files::collectord]Collectord’s own logmacos_collectord

As on every platform, Collectord on a Mac also scrapes Prometheus endpoints ([input.prometheus::<name>]) and runs your own scripts ([input.script::<name>]). 001-general.conf below carries a commented example of each. Their metrics go to the metrics index like every other stat, and a script runs with the Mac’s own tools. The Collectord section covers the features every product shares.

The Linux inputs that read procfs or cgroups have nothing to read on a Mac: [input.proc_stats], [input.net_stats], [input.net_socket_table], [input.disk_stats], [input.journald], [input.mount_stats] and [input.systemd_units]. A configuration that turns one on does not start, and the error names the macOS input that covers it.

Reference

The shipped 001-general.conf, with every section and key and inline comments:

001-general.conf ini
  1# An upgrade replaces this file: put your settings in 002-user.conf, whose keys override these
  2# even when empty. An environment variable COLLECTOR__<ANYNAME>=<section>__<key>=<value> overrides
  3# both files, and a configuration profile for com.outcoldsolutions.collectord overrides them all.
  4
  5[general]
  6
  7# Please review license https://www.outcoldsolutions.com/legal/license-agreement/
  8# and accept it with acceptLicense = true in 002-user.conf
  9acceptLicense = false
 10
 11# The read positions, internal state and pid file. Moving it loses the state (the files, crash
 12# reports and inventory are sent again), and the pid file path in
 13# /etc/newsyslog.d/collectorformacos.conf must follow, after every upgrade too, or the rotated log
 14# is never reopened.
 15dataPath = /opt/collectorformacos/var/collectord
 16
 17# log level (trace, debug, info, warn, error, fatal)
 18logLevel = info
 19
 20# How Collectord spells the fields it composes: _ (the default) or .; the monitoring app reads both
 21# fieldsSeparator = _
 22
 23# host:port of the http server (empty: none), serving /healthz and /readyz, and
 24# /metrics/prometheus and /metrics/json with httpServerEndpoints.metrics = true
 25httpServerBinding =
 26
 27# telemetry report endpoint, set it to empty string to disable telemetry
 28telemetryEndpoint = https://license.outcold.solutions/telemetry/
 29
 30licenseEndpoint = https://license.outcold.solutions/license/
 31licenseServerProxyUrl =
 32
 33# user:password
 34licenseServerProxyBasicAuth =
 35
 36license =
 37
 38# Empty: the HostName set with scutil --set HostName, else the local host name (System Settings >
 39# General > Sharing), which stays the same across networks. launchd sets no HOSTNAME to expand.
 40hostname =
 41
 42# splunk, or devnull to send nothing
 43defaultOutput = splunk
 44
 45fileInputBufferSize = 8kb
 46fileInputLineMaxSize = 1mb
 47
 48# Indexed fields added to every event and record, named to match ^[a-z][_a-z0-9]*$
 49# ; fields.my_environment = dev
 50# macos_cluster is the fleet label the monitoring app's dashboards filter by (ci, laptops, ...)
 51fields.macos_cluster = -
 52
 53# Bytes of events forwarded a second, such as 512Kb, past which a source waits (the stats are not
 54# capped)
 55thruputPerSecond =
 56
 57# Drop the events older than this, such as 168h, or this far in the future, such as 1h
 58tooOldEvents =
 59tooNewEvents =
 60
 61
 62[license.client]
 63# A license on a web server, or served by a Collectord license server
 64;url = http://10.0.2.2:9199/license
 65;basicAuth = :password
 66insecure = false
 67capath =
 68caname =
 69
 70
 71[input.collectord_metrics]
 72
 73disabled = false
 74type = macos_prometheus
 75interval = 1m
 76output =
 77index =
 78
 79# macOS sends every stat, scrape and format = prometheus script to a metrics index: metricsIndex,
 80# else [output.splunk] defaultMetricsIndex, else index, else the HEC token's default index (normally
 81# an events index, which stores them as events). metricsOutput: an output whose token can write it.
 82metricsIndex =
 83metricsOutput =
 84
 85# Regular expressions on the metric name: with a whitelist, only the matching metrics are sent
 86whitelist.1 = ^file_input_open$
 87whitelist.2 = ^file_input_read_bytes$
 88whitelist.3 = ^pipe$
 89whitelist.4 = ^pipelines_num$
 90whitelist.5 = ^splunk_post_bytes_sum.*$
 91whitelist.6 = ^splunk_post_events_count_sum.*$
 92whitelist.7 = ^splunk_post_failed_requests$
 93whitelist.8 = ^splunk_post_message_max_lag_seconds_bucket.*$
 94whitelist.9 = ^splunk_post_requests_seconds_sum.*$
 95whitelist.10 = ^splunk_post_retries_required_sum.*$
 96# a whitelisted _sum brings its _count; these two repeat splunk_post_requests_seconds_count
 97blacklist.1 = ^splunk_post_(bytes|events_count)_count$
 98
 99# Scrape a Prometheus endpoint (an exporter, an application's /metrics), one
100# [input.prometheus::<name>] section each; the first of endpoint.1, endpoint.2, ... that answers
101# is scraped. podSelector, endpointSlice, service and nodeSelector need Kubernetes: a section with
102# one stops collectord from starting.
103; [input.prometheus::node_exporter]
104; type = macos_prometheus
105; host =
106; source = node_exporter
107; interval = 60s
108; endpoint.1 = http://127.0.0.1:9100/metrics
109# token for "Authorization: Bearer $(cat tokenPath)"
110; tokenPath =
111# the CA that signs the server's certificate
112; certPath =
113; clientCertPath =
114; clientKeyPath =
115; insecure = false
116; metricsIndex =
117; metricsOutput =
118
119
120# Run an executable every interval and send what it prints, one [input.script::<name>] section
121# each. It runs without a shell, as root unless user says, with a fixed environment (PATH,
122# LANG=C, HOME, the COLLECTORD_* variables, then env.<n>), never Collectord's, and only while it
123# and every directory above it are owned by root and writable by no one else. A change to these
124# sections takes a restart.
125; [input.script::uptime]
126; disabled = false
127; command = /Library/Application Support/Scripts/uptime.sh
128; arg.1 = --format
129; arg.2 = json
130; env.1 = TZ=UTC
131; interval = 5m
132; startDelay = 0s
133# runs never overlap, so it may be longer than interval
134; timeout = 60s
135# event: all of the output is one event; lines: one event per line; prometheus: see below
136; format = event
137# with format = lines, a line this does not match continues the event before it
138; eventPattern =
139# a name or uid, optionally :group or :gid; empty runs as root
140; user = nobody
141; workingDirectory = /
142# a run printing more is stopped: format = lines sends the complete lines before it, the others nothing
143; maxOutputSize = 1MB
144# the events' sourcetype (default is the section's name) and source (default is command)
145; type = macos_uptime
146; source =
147; index =
148; output =
149
150# With format = prometheus a script prints a Prometheus text exposition (what node_exporter's
151# textfile collector reads): each sample is a metrics-index record.
152; [input.script::backup_metrics]
153; disabled = false
154; command = /Library/Application Support/Scripts/backup-metrics.sh
155; interval = 1m
156; user = nobody
157; format = prometheus
158; metricsIndex =
159; metricsOutput =
160; whitelist.1 = ^backup_
161; blacklist.1 =
162; type = macos_backup
163
164
165[general.macos]
166
167# auto (a Mac with a battery is a laptop, any other a desktop), laptop, desktop or rack: nothing on
168# a Mac tells a racked Mac mini from one on a desk
169hardwareClass = auto
170
171
172[input.system_stats]
173
174disabled.host = false
175statsInterval = 30s
176type.host = macos_stats_host
177index.host =
178output.host =
179metricsIndex.host =
180metricsOutput.host =
181
182
183[input.macos_stats]
184
185disabled = false
186statsInterval = 30s
187type = macos_stats
188index =
189output =
190metricsIndex =
191metricsOutput =
192cpu = true
193cpu.perCore = true
194gpu = true
195power = true
196
197# When the chip's energy counters stand still (macOS 27), keep /usr/bin/powermetrics sampling once
198# an interval (up to 0.2% of a core at 30s) to move them; off, only the GPU's and the whole Mac's
199# power are sent
200power.powermetrics = true
201
202thermals = true
203disks = true
204filesystems = true
205filesystems.exclude = ^/(dev|System/Volumes/(VM|Preboot|Update|xarts|iSCPreboot|Hardware)|Volumes/Recovery)(/|$)
206filesystems.remote = false
207
208# physical interfaces only, unless network.virtual (VM bridges) or network.tunnels (VPN tunnels)
209network = true
210network.virtual = false
211network.tunnels = false
212network.exclude =
213
214
215[input.macos_processes]
216
217# off, program names still reach Splunk in the log entries, crash reports and noise sampler
218disabled = false
219
220statsInterval = 30s
221type = macos_proc_stats
222index =
223output =
224metricsIndex =
225metricsOutput =
226
227# executables sent by CPU and, separately, by memory; the rest fold into (other)
228top = 20
229
230# executables always sent
231include = ^(com\.apple\.Virtualization\.VirtualMachine|xcodebuild|swift-frontend|clang|ld|Simulator|launchd_sim|collectord)$
232
233# per-VM records for Virtualization-framework guests
234vms = true
235
236# busy_process host events, sent through [input.macos_events], name a process over busy.cores at
237# two readings running, its path and its user: when it starts, every busy.every, and when it ends
238busy = true
239
240# cores of CPU; a thread spinning flat out reads just under one
241busy.cores = 0.9
242
243# processes followed at once, the busiest first
244busy.processes = 5
245
246busy.every = 15m
247
248
249[input.macos_status]
250
251disabled = false
252statsInterval = 60s
253type = macos_status
254index =
255output =
256metricsIndex =
257metricsOutput =
258
259# FileVault, SIP, Gatekeeper, the firewall, MDM, sharing and login settings, the administrators
260posture = true
261posture.interval = 1h
262
263# the last scheduled update check's list (softwareupdate --list --no-scan)
264updates = true
265updates.interval = 6h
266
267battery = true
268
269# the lid, and whether sleep is prevented (never by which process) or disabled
270powerState = true
271
272# the console user, every terminal, SSH and background session, and each login and logout
273users = true
274
275# the system domain's services; those include matches and exclude does not are sent one by one
276launchd = true
277launchd.include = .*
278launchd.exclude = ^com\.apple\.
279
280# Xcode versions, and every home's DerivedData and simulator storage: about 4 s of CPU a walk
281xcode = true
282xcode.interval = 6h
283xcode.maxFiles = 200000
284
285# Host events when they change and every inventory.interval: each interface's addresses and MAC
286# (never the temporary IPv6 ones), the local accounts and which are administrators, and the launch
287# items of /Library and every home's ~/Library/LaunchAgents, never their arguments
288interfaces = true
289accounts = true
290accounts.interval = 1h
291launchItems = true
292launchItems.interval = 5m
293# the login and background items System Settings lists, with whether each is allowed
294backgroundItems = true
295backgroundItems.interval = 1h
296# raise Monitoring macOS's macro_macos_inventory_lookback_seconds (13 hours) with this
297inventory.interval = 12h
298
299# the macOS Security Compliance Project's results (/Library/Preferences/org.<baseline>.audit.plist)
300# where the organization runs its script; nothing from a Mac that runs no scan
301compliance = true
302compliance.interval = 1h
303
304# the first posture, update, Xcode, accounts, launch items, background items and compliance reads
305# run this long after start
306startDelay = 2m
307
308
309# Off also stops the host events the processes and status inputs send through it: busy processes,
310# logins, launchd services, posture and update changes, the inventory
311[input.macos_events]
312
313disabled = false
314type = macos_host_events
315type.launchd = macos_launchd
316index =
317output =
318
319
320# Crash reports and kernel panics (.ips and .panic files), sent once each as a summary.
321[input.macos_crash_reports]
322
323disabled = false
324type = macos_crash_report
325index =
326output =
327scanInterval = 1m
328
329# also read every user's ~/Library/Logs/DiagnosticReports (their paths name the user)
330userDirectories = true
331
332# larger reports are skipped
333maxFileSize = 8mb
334
335# on the first start, reports older than this are skipped
336startFromRel = 24h
337
338
339# TCP and UDP connections, one event per process, protocol, direction, remote address and service
340# port, and the listening sockets: sent when first seen, again while open, and when closed; one
341# opened and closed between two reads is never seen
342[input.macos_connections]
343
344disabled = false
345type = macos_connections
346index =
347output =
348interval = 60s
349
350# how often a connection group still open is sent again
351idleInterval = 15m
352
353# how often a listening socket still open is sent again
354listenersInterval = 30m
355
356# also send connections to 127.0.0.0/8 and ::1; one to the Mac's own address is sent either way
357loopback = false
358
359# connection groups one read sends, and listeners, each; the rest fold into (other)
360maxGroups = 1000
361
362# each connection's bytes and interface, through nettop: about 35 ms of CPU a sample
363traffic = true
364
365# at most once a read; longer costs less, and misses the bytes of a connection opened and closed
366# between two samples
367traffic.interval = 1m
368
369
370# The apps in /Applications and one folder below it: every one each snapshotInterval, and the
371# installs, updates and removals found each interval
372[input.macos_apps]
373
374disabled = false
375type = macos_apps
376index =
377output =
378interval = 1h
379
380# under a day, so a day's window sees every app
381snapshotInterval = 12h
382
383startDelay = 2m
384
385# also read every user's ~/Applications (its paths name the user)
386userDirectories = true
387
388
389[input.macos_logs]
390
391disabled = false
392type = macos_logs
393type.samples = macos_log_samples
394index =
395output =
396
397# entries a template (process, subsystem, level, format string) sends a minute; past it, one
398# "seen N times" event a minute until it calms down
399rateLimit = 60
400
401# entries a pack sends a minute, whatever their templates; the rest are only counted
402packRateLimit = 300
403
404# send no entries, only per-template counts ([input.macos_log_counts])
405countsOnly = false
406
407# after a restart or a wake, how far back log show reads to close the gap; older entries are lost
408catchUp = 1h
409
410# Every noiseSampler.every, count the whole log's templates over noiseSampler.window and send the
411# top ones; noiseSampler.samples adds each one's first message, from whichever process wrote it
412noiseSampler = true
413noiseSampler.every = 15m
414noiseSampler.window = 30s
415noiseSampler.top = 50
416noiseSampler.samples = true
417noiseSampler.startDelay = 15m
418
419
420# Log packs: subsystem.<n> (and those below it) and process.<n> read default, error and fault
421# entries; subsystem.error.<n> and process.error.<n> errors and faults only, .info.<n> and
422# .debug.<n> that level too. A process selector takes its libraries' entries too; one named by path
423# drops a same-named executable elsewhere from every pack. An entry is the first pack's, by name,
424# that selects and keeps it; whitelist.<n> and blacklist.<n> filter only after log stream reads it.
425
426# powerd and launchd at error level: at the default one powerd names every process that holds off
427# sleep, and launchd writes some 25 lines per service it starts. log stream never delivers
428# launchd's entries: they are read from the log store every five minutes, up to five minutes late.
429[input.macos_logs::workloads]
430disabled = false
431subsystem.1 = com.apple.Virtualization
432subsystem.2 = com.apple.xpc.launchd
433subsystem.3 = com.apple.launchd
434subsystem.4 = com.apple.DiskArbitration
435subsystem.5 = com.apple.diskmanagement
436subsystem.6 = com.apple.thermalmonitord
437subsystem.error.1 = com.apple.powerd
438subsystem.8 = com.apple.dt.Xcode
439subsystem.9 = com.apple.CoreSimulator
440subsystem.10 = com.apple.kernel
441process.error.1 = launchd
442process.2 = com.apple.Virtualization.VirtualMachine
443process.3 = diskarbitrationd
444process.4 = thermalmonitord
445process.6 = xcodebuild
446process.7 = Simulator
447
448# loginwindow, softwareupdated and mdmclient at error level: at the default one loginwindow names
449# every app a person opens and quits, and the three write thousands of entries an hour
450[input.macos_logs::fleet_health]
451disabled = false
452subsystem.error.1 = com.apple.SoftwareUpdate
453subsystem.error.2 = com.apple.softwareupdate
454subsystem.3 = com.apple.install
455subsystem.error.4 = com.apple.loginwindow
456subsystem.6 = com.apple.ReportCrash
457subsystem.error.7 = com.apple.mdmclient
458subsystem.error.8 = com.apple.ManagedClient
459subsystem.9 = com.apple.TimeMachine
460subsystem.10 = com.apple.backupd
461subsystem.error.11 = com.apple.SoftwareUpdateMacController
462process.2 = installd
463process.4 = ReportCrash
464process.6 = backupd
465
466# Off for its cost: log reads every kernel entry to find the errors, about 0.8% of a core on a busy
467# Mac (1.3% at the default level)
468[input.macos_logs::kernel]
469disabled = true
470process.error.1 = kernel
471
472# Its messages name accounts (sshd's "Invalid user alice", sudo's command lines). sudo and sshd are
473# named by path, so a binary of that name elsewhere cannot forge them. With fleet_health on, the
474# login window's and ManagedClient's errors are fleet_health's.
475[input.macos_logs::security]
476disabled = false
477subsystem.1 = com.apple.sudo
478subsystem.2 = com.apple.sshd
479subsystem.3 = com.apple.xprotect
480subsystem.4 = com.apple.Authorization
481subsystem.5 = com.apple.alf
482subsystem.6 = com.apple.securityd.authorization
483subsystem.error.1 = com.apple.loginwindow
484subsystem.error.2 = com.apple.screensharing
485subsystem.error.3 = com.apple.syspolicy
486subsystem.error.4 = com.apple.opendirectoryd
487subsystem.error.5 = com.apple.ManagedClient
488process.1 = /usr/bin/sudo
489process.3 = XProtect
490process.info.1 = /usr/libexec/sshd-session
491process.info.2 = /usr/sbin/sshd
492process.error.1 = screensharingd
493process.error.3 = opendirectoryd
494process.error.5 = authd
495# These drop the library chatter inside sshd and sudo, 150 to 1,000 lines a day a Mac, none of it
496# about who logged in or ran what: copy them without the ";" under this section in 002-user.conf.
497# macOS 15 and later turn sudo's log_allowed off: this pack then gets sudo's refusals, never the
498# commands it ran (the posture's sudo_log_allowed and collectord verify say which Macs log them).
499; blacklist.1 = ^send failed:
500; blacklist.2 = ^Too many groups requested \(
501; blacklist.3 = ^Reading( \S+)? config$
502; blacklist.4 = ^networkd_settings_read_from_file(_locked)?\b
503; blacklist.5 = ^\[0x[0-9a-f]+\] (activating connection|invalidated after the last release of the connection object)
504; blacklist.6 = ^Using original path \(null\)$
505
506
507# The log input's counts share its reader: an output that takes none of them for 10 seconds holds
508# the log entries up that long, then drops the counts, never the entries
509[input.macos_log_counts]
510
511disabled = false
512type = macos_log_counts
513index =
514output =
515metricsIndex =
516metricsOutput =
517
518
519# On the first start the whole file is read (tens of MB on an older Mac), and only its last day sent
520[input.files::install_log]
521
522disabled = false
523path = /var/log/
524match = ^install\.log$
525
526# how often a file read to its end is checked for more; each check wakes a laptop
527pollingInterval = 5s
528
529# how often path is searched for new files
530walkingInterval = 1m
531
532# add the file offset to the events
533verboseFields = false
534
535type = macos_install_log
536index =
537
538# 2026-09-25 01:05:37-04 host process[pid]: message. Every named group is an indexed field, so the
539# host and the pid are left out. An empty message, as the older year-less format leaves, is not sent.
540extraction = ^(?:(?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[+-]\d{2})\s[^\s]+\s(?P<syslog_component>[^:\[]+)(?:\[\d+\])?: (?P<message>(?s:.*))|[A-Z][a-z]{2} [ \d]\d \d{2}:\d{2}:\d{2} (?P<message>)(?s:.*))$
541extractionMessageField = message
542
543# the extracted fields naming the process that wrote a line, which groups its lines apart
544extractionWriterFields = syslog_component
545
546timestampField = timestamp
547
548# a Go layout of the reference time `Mon Jan 2 15:04:05 -0700 MST 2006`
549timestampFormat = 2006-01-02 15:04:05-07
550
551# the time zone when the format has none
552timestampLocation = Local
553
554# the percent of lines forwarded: 20 sends 20%, -1 all of them
555samplingPercent = -1
556
557# hash-based sampling: a regular expression with a named group `key`
558samplingKey =
559
560output =
561thruputPerSecond =
562tooOldEvents = 24h
563tooNewEvents =
564
565# a line this does not match continues the event before it
566eventPattern = ^[^\s]
567
568# Group each file's repeated lines into one event per run that counts them. Off unless true.
569repeatEnabled = false
570# How long a run is held before its event goes out, up to 10m (a crash resends up to that much)
571# repeatMaxSpan = 1m
572# Add every line's time to a run's event (collectord_repeat_offsets, milliseconds from its own)
573# repeatOffsets = false
574# What each stream may remember: distinct lines, lines one event stands for, and bytes
575# repeatMaxKeys = 256
576# repeatMaxCount = 1000
577# repeatMaxBytes = 256KB
578
579# Fold each file's lines of one pattern past foldMaxPerMinute into one summary a minute.
580# Lossy: folded lines are not sent. Off unless true.
581foldEnabled = false
582# Lines of one pattern a minute sent before the rest fold
583# foldMaxPerMinute = 60
584# Lines never folded (a regular expression; empty: the default)
585# foldKeep = (?i)error|exception|fatal|panic
586# What each file may keep a minute: its patterns and summaries
587# foldMaxBytes = 256KB
588
589# Report each file's top patterns every interval, as events of their own. Off unless true.
590patternsEnabled = false
591# How often a report goes out, from 1m to 24h
592# patternsInterval = 15m
593# How many patterns a report carries, up to 100
594# patternsTop = 20
595# What each file's patterns may keep; past it a new one takes the place of the lightest
596# patternsMaxBytes = 256KB
597# The report events' type (empty: this section's type with _patterns after it)
598# patternsType =
599
600
601# Collectord's own log, which the monitoring app's Collectors page and alerts read
602[input.files::collectord]
603
604disabled = false
605path = /Library/Logs/collectorformacos/
606match = ^collectord\.log$
607pollingInterval = 5s
608walkingInterval = 30s
609verboseFields = false
610type = macos_collectord
611index =
612
613# INFO 2026/09/25 05:29:32.966289 file.go:34: ...: the whole line stays the message, level and
614# all, as the app's licence searches read it
615extraction = ^[A-Z]+ (?P<timestamp>\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}\.\d{6}) (?s:.*)$
616
617timestampField = timestamp
618timestampFormat = 2006/01/02 15:04:05.000000
619timestampLocation = Local
620samplingPercent = -1
621samplingKey =
622output =
623thruputPerSecond =
624tooOldEvents =
625tooNewEvents =
626eventPattern = ^[A-Z]+ \d{4}/\d{2}/\d{2}\s
627
628# Group each file's repeated lines into one event per run that counts them. Off unless true.
629repeatEnabled = false
630# How long a run is held before its event goes out, up to 10m (a crash resends up to that much)
631# repeatMaxSpan = 1m
632# Add every line's time to a run's event (collectord_repeat_offsets, milliseconds from its own)
633# repeatOffsets = false
634# What each stream may remember: distinct lines, lines one event stands for, and bytes
635# repeatMaxKeys = 256
636# repeatMaxCount = 1000
637# repeatMaxBytes = 256KB
638
639# Fold each file's lines of one pattern past foldMaxPerMinute into one summary a minute.
640# Lossy: folded lines are not sent. Off unless true.
641foldEnabled = false
642# Lines of one pattern a minute sent before the rest fold
643# foldMaxPerMinute = 60
644# Lines never folded (a regular expression; empty: the default)
645# foldKeep = (?i)error|exception|fatal|panic
646# What each file may keep a minute: its patterns and summaries
647# foldMaxBytes = 256KB
648
649# Report each file's top patterns every interval, as events of their own. Off unless true.
650patternsEnabled = false
651# How often a report goes out, from 1m to 24h
652# patternsInterval = 15m
653# How many patterns a report carries, up to 100
654# patternsTop = 20
655# What each file's patterns may keep; past it a new one takes the place of the lightest
656# patternsMaxBytes = 256KB
657# The report events' type (empty: this section's type with _patterns after it)
658# patternsType =
659
660
661[output.splunk]
662
663url =
664# several HEC URLs, all with the same path:
665# urls.0 = https://server1:8088/services/collector/event/1.0
666# urls.1 = https://server1:8088/services/collector/event/1.0
667
668# how a URL is picked from several, at first and after each failure (connection or HTTP 5xx):
669# urlSelection = random|round-robin|random-with-round-robin
670# random picks at random, at first and after each failure; random-with-round-robin and round-robin
671# take the next URL after a failure, so the instances on a failed URL can all move to the same one
672urlSelection = random
673
674token =
675insecure = false
676caPath =
677caName =
678clientCertPath =
679clientKeyPath =
680
681# a batch goes out at batchSize, at events, or after frequency
682frequency = 5s
683batchSize = 768K
684# 0: no limit
685events = 50
686
687proxyUrl =
688
689# user:password
690proxyBasicAuth =
691
692# Splunk acknowledgement url (.../services/collector/ack)
693ackUrl =
694
695ackEnabled = false
696ackTimeout = 3m
697
698# per request, connecting and reading the response included
699timeout = 30s
700
701# a client per index, so events with an incorrect index do not block the other pipelines
702dedicatedClientPerIndex = true
703
704# RedirectToDefault, Drop or Retry
705incorrectIndexBehavior = RedirectToDefault
706
707# gzip compression level (nocompression, default, 1...9)
708compressionLevel = default
709
710# more threads for over 4k events a second
711threads = 1
712
713# roundrobin, or weighted (beta)
714threadsAlgorithm = weighted
715
716# Drop the events that name no index, instead of sending them to the HEC token's default index
717; requireExplicitIndex = true
718
719# The metrics index of every input with no metricsIndex of its own; 002-user.conf sets it to
720# macos_metrics, the one the monitoring app reads
721; defaultMetricsIndex = macos_metrics
722
723# Truncate messages longer than this
724; maximumMessageLength = 1M
725
726# Events queued for the output: more rides out longer network trouble, at the cost of memory
727queueSize = 1024
728
729# Digits of the timestamps' fraction: 3, milliseconds (the default); 6, microseconds; 9, nanoseconds
730; timestampPrecision = 3