fleet/cmd/osquery-perf/osquery_perf/stats.go
Martin Angers ade597b5e1
DDMV: improve osquery-perf simulation of DDM traffic (#43607)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #43050 

## Testing

- [x] QA'd all new/changed functionality manually

Confirmed the traffic sequence with ngrok and DDM stats are as expected
in the osquery-perf logs:

### Adding a new DDM

* `DeclarativeManagement` command and Ack
* `tokens` request
* `declaration-items` request
* `activation` for the DDM
* `configuration` for the DDM
* `tokens` request confirms changes settled
* `status` request

### Remove/re-add DDM (no global change)

* `DeclarativeManagement` command and Ack
* `tokens` request

### Adding a second DDM

* `DeclarativeManagement` command and Ack
* `tokens` request
* `declaration-items` request
* `activation` for the new DDM only
* `configuration` for the new DDM only
* `tokens` request confirms changes settled
* `status` request

### Removing a DDM

* `DeclarativeManagement` command and Ack
* `tokens` request
* `declaration-items` request
* `tokens` request
* `status` request

### Remove all DDMs

* `DeclarativeManagement` command and Ack
* `tokens` request
* `declaration-items` request
* `tokens` request
* `status` request

---

State correctly updates on the host's profiles:

<img width="1246" height="512" alt="image"
src="https://github.com/user-attachments/assets/0d289d4e-1e9b-4283-aef0-fd1ab3ecb355"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved macOS Declarative Management sync: faster convergence,
fetches only changed declarations, detects removals, and sends
consolidated status updates.

* **Monitoring**
* Added metrics to track declaration token fetch success and error
rates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-21 13:26:46 -04:00

289 lines
6.1 KiB
Go

package osquery_perf
import (
"log"
"sync"
"time"
)
type Stats struct {
StartTime time.Time
errors int
osqueryEnrollments int
orbitEnrollments int
mdmEnrollments int
mdmSessions int
distributedWrites int
mdmCommandsReceived int
distributedReads int
configRequests int
configErrors int
resultLogRequests int
orbitErrors int
mdmErrors int
ddmTokensErrors int
ddmTokensSuccess int
ddmDeclarationItemsErrors int
ddmConfigurationErrors int
ddmActivationErrors int
ddmStatusErrors int
ddmDeclarationItemsSuccess int
ddmConfigurationSuccess int
ddmActivationSuccess int
ddmStatusSuccess int
desktopErrors int
distributedReadErrors int
distributedWriteErrors int
resultLogErrors int
bufferedLogs int
scriptExecs int
scriptExecErrs int
softwareInstalls int
softwareInstallErrs int
l sync.Mutex
}
func (s *Stats) IncrementErrors(errors int) {
s.l.Lock()
defer s.l.Unlock()
s.errors += errors
}
func (s *Stats) IncrementEnrollments() {
s.l.Lock()
defer s.l.Unlock()
s.osqueryEnrollments++
}
func (s *Stats) IncrementOrbitEnrollments() {
s.l.Lock()
defer s.l.Unlock()
s.orbitEnrollments++
}
func (s *Stats) IncrementMDMEnrollments() {
s.l.Lock()
defer s.l.Unlock()
s.mdmEnrollments++
}
func (s *Stats) IncrementMDMSessions() {
s.l.Lock()
defer s.l.Unlock()
s.mdmSessions++
}
func (s *Stats) IncrementDistributedWrites() {
s.l.Lock()
defer s.l.Unlock()
s.distributedWrites++
}
func (s *Stats) IncrementMDMCommandsReceived() {
s.l.Lock()
defer s.l.Unlock()
s.mdmCommandsReceived++
}
func (s *Stats) IncrementDistributedReads() {
s.l.Lock()
defer s.l.Unlock()
s.distributedReads++
}
func (s *Stats) IncrementConfigRequests() {
s.l.Lock()
defer s.l.Unlock()
s.configRequests++
}
func (s *Stats) IncrementConfigErrors() {
s.l.Lock()
defer s.l.Unlock()
s.configErrors++
}
func (s *Stats) IncrementResultLogRequests() {
s.l.Lock()
defer s.l.Unlock()
s.resultLogRequests++
}
func (s *Stats) IncrementOrbitErrors() {
s.l.Lock()
defer s.l.Unlock()
s.orbitErrors++
}
func (s *Stats) IncrementMDMErrors() {
s.l.Lock()
defer s.l.Unlock()
s.mdmErrors++
}
func (s *Stats) IncrementDDMTokensErrors() {
s.l.Lock()
defer s.l.Unlock()
s.ddmTokensErrors++
}
func (s *Stats) IncrementDDMTokensSuccess() {
s.l.Lock()
defer s.l.Unlock()
s.ddmTokensSuccess++
}
func (s *Stats) IncrementDDMDeclarationItemsErrors() {
s.l.Lock()
defer s.l.Unlock()
s.ddmDeclarationItemsErrors++
}
func (s *Stats) IncrementDDMConfigurationErrors() {
s.l.Lock()
defer s.l.Unlock()
s.ddmConfigurationErrors++
}
func (s *Stats) IncrementDDMActivationErrors() {
s.l.Lock()
defer s.l.Unlock()
s.ddmActivationErrors++
}
func (s *Stats) IncrementDDMStatusErrors() {
s.l.Lock()
defer s.l.Unlock()
s.ddmStatusErrors++
}
func (s *Stats) IncrementDDMDeclarationItemsSuccess() {
s.l.Lock()
defer s.l.Unlock()
s.ddmDeclarationItemsSuccess++
}
func (s *Stats) IncrementDDMConfigurationSuccess() {
s.l.Lock()
defer s.l.Unlock()
s.ddmConfigurationSuccess++
}
func (s *Stats) IncrementDDMActivationSuccess() {
s.l.Lock()
defer s.l.Unlock()
s.ddmActivationSuccess++
}
func (s *Stats) IncrementDDMStatusSuccess() {
s.l.Lock()
defer s.l.Unlock()
s.ddmStatusSuccess++
}
func (s *Stats) IncrementDesktopErrors() {
s.l.Lock()
defer s.l.Unlock()
s.desktopErrors++
}
func (s *Stats) IncrementDistributedReadErrors() {
s.l.Lock()
defer s.l.Unlock()
s.distributedReadErrors++
}
func (s *Stats) IncrementDistributedWriteErrors() {
s.l.Lock()
defer s.l.Unlock()
s.distributedWriteErrors++
}
func (s *Stats) IncrementResultLogErrors() {
s.l.Lock()
defer s.l.Unlock()
s.resultLogErrors++
}
func (s *Stats) UpdateBufferedLogs(v int) {
s.l.Lock()
defer s.l.Unlock()
s.bufferedLogs += v
if s.bufferedLogs < 0 {
s.bufferedLogs = 0
}
}
func (s *Stats) IncrementScriptExecs() {
s.l.Lock()
defer s.l.Unlock()
s.scriptExecs++
}
func (s *Stats) IncrementScriptExecErrs() {
s.l.Lock()
defer s.l.Unlock()
s.scriptExecErrs++
}
func (s *Stats) IncrementSoftwareInstalls() {
s.l.Lock()
defer s.l.Unlock()
s.softwareInstalls++
}
func (s *Stats) IncrementSoftwareInstallErrs() {
s.l.Lock()
defer s.l.Unlock()
s.softwareInstallErrs++
}
func (s *Stats) Log() {
s.l.Lock()
defer s.l.Unlock()
log.Printf(
"uptime: %s, error rate: %.2f, osquery enrolls: %d, orbit enrolls: %d, mdm enrolls: %d, distributed/reads: %d, distributed/writes: %d, config requests: %d, result log requests: %d, mdm sessions initiated: %d, mdm commands received: %d, config errors: %d, distributed/read errors: %d, distributed/write errors: %d, log result errors: %d, orbit errors: %d, desktop errors: %d, mdm errors: %d, ddm tokens success: %d, ddm tokens errors: %d, ddm declaration items success: %d, ddm declaration items errors: %d, ddm activation success: %d, ddm activation errors: %d, ddm configuration success: %d, ddm configuration errors: %d, ddm status success: %d, ddm status errors: %d, buffered logs: %d, script execs (errs): %d (%d), software installs (errs): %d (%d)",
time.Since(s.StartTime).Round(time.Second),
float64(s.errors)/float64(s.osqueryEnrollments),
s.osqueryEnrollments,
s.orbitEnrollments,
s.mdmEnrollments,
s.distributedReads,
s.distributedWrites,
s.configRequests,
s.resultLogRequests,
s.mdmSessions,
s.mdmCommandsReceived,
s.configErrors,
s.distributedReadErrors,
s.distributedWriteErrors,
s.resultLogErrors,
s.orbitErrors,
s.desktopErrors,
s.mdmErrors,
s.ddmTokensSuccess,
s.ddmTokensErrors,
s.ddmDeclarationItemsSuccess,
s.ddmDeclarationItemsErrors,
s.ddmActivationSuccess,
s.ddmActivationErrors,
s.ddmConfigurationSuccess,
s.ddmConfigurationErrors,
s.ddmStatusSuccess,
s.ddmStatusErrors,
s.bufferedLogs,
s.scriptExecs,
s.scriptExecErrs,
s.softwareInstalls,
s.softwareInstallErrs,
)
}
func (s *Stats) RunLoop() {
ticker := time.Tick(10 * time.Second)
for range ticker {
s.Log()
}
}