Wednesday, January 28, 2026

Enabling Chef Logs in Windows Event Viewer

Chef is a desired configuration management tool used to configure multiple systems into the same, identical state. When Chef desired state configuration scripts fail on a few systems, troubleshooting becomes difficult without proper logging, because each failed system must be checked individually.

However, if logs are available centrally, for example, in the ELK stack, it becomes much easier to troubleshoot issues.

In this blog, we will learn how to enable Chef logs as Windows Event Logs. Once the logs are enabled, these Windows Event Logs can be forwarded to ELK, allowing centralized log analysis and faster troubleshooting.

Pre-requisites:
Windows servers are configured and managed using Chef


First, let’s look at the default Chef logs. By default, Chef writes logs to the chef-client.log file located in C:\chef.  The default logs look as below.

Recipe: instance::chrome

  * remote_file[C:/Installers/GoogleChromeStandaloneEnterprise64.msi] action create_if_missing (up to date)

  * windows_package[GoogleChromeStandaloneEnterprise64.msi] action install (skipped due to not_if)



Now, let’s enable Windows Event Logs for Chef. To do this, open the client.rb file located in C:\chef and find the log_location STDOUT setting. To enable Windows Event Logs, remove STDOUT and set the log_location value to :win_evt.

After changing the log location, the chef-client.log format changes and looks similar to the example below.

[2025-12-03T20:00:21+01:00] INFO: Processing remote_file[C:/Installers/GoogleChromeStandaloneEnterprise64.msi] action create_if_missing (instance::chrome line 6)

[2025-12-03T20:00:21+01:00] INFO: Processing windows_package[GoogleChromeStandaloneEnterprise64.msi] action install (instance::chrome line 11)



Additionally, the Chef logs should now be available in the Windows Event Log, as shown in the image below.




The following PowerShell script can be used in an Azure DevOps pipeline to enable Chef logs as Windows Event Logs across multiple servers.


$ChefConfigPath = 'C:\chef\client.rb';

$LogLocation = ':win_evt';


Write-Host "=== Chef Configuration Update Script ==="

Write-Host "Configuration file: $ChefConfigPath"

Write-Host "Target log_location: $LogLocation"

 

try {

    # Check if file exists

    if (-not (Test-Path $ChefConfigPath)) {

        Write-Error "Chef configuration file not found: $ChefConfigPath"

        exit 1

    }


    # Create backup

    $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"

    $backupPath = "$ChefConfigPath.backup.$timestamp"

    Copy-Item $ChefConfigPath $backupPath -Force

    Write-Host "Backup created: $backupPath"


    # Read current content

    $content = Get-Content $ChefConfigPath

    Write-Host "Current configuration:"

    $content | ForEach-Object { Write-Host "  $_" }

 

    # Update configuration

    $newContent = @()

    $logLevelUpdated = $false

    $logLocationUpdated = $false

 

    foreach ($line in $content) {

        switch -Regex ($line) {

            '^\s*log_location\s+' {

                $newContent += "log_location     $LogLocation"

                $logLocationUpdated = $true

                Write-Host "Updated log_location to: $LogLocation"

                break

            }

            default {

                $newContent += $line

            }

        }

    }

 

    # Write updated content

    $newContent | Set-Content $ChefConfigPath -Encoding UTF8

 

} catch {

    Write-Error "Error updating Chef configuration: $($_.Exception.Message)"

    Write-Host "Stack trace: $($_.ScriptStackTrace)"

    exit 1

}

No comments:

Post a Comment