Replacing ServiceMonitor.exe with IIS error log events in windows IIS container

ServiceMonitor.exe is used as default ENTRYPOINT entry official Microsoft IIS build. It does not seem to be doing much except for checking if service W3SVC is running. There is multitude of issues with this EXE based on github (https://github.com/Microsoft/iis-docker/issues). Bearing in mind very limited functionality that this EXE provides I decided it to replace with something more useful.
Starting with IIS 8.5 it’s possible to output IIS logs not only to log files but also to ETW events. You can consume those inside eventlog name called Microsoft-Windows-IIS-Logging/Logs which shall be enabled to receive those events. Steps below will allow to provide output of all errors being logged on your webserver to docker logs instead of default ENTRYPOINT of IIS image which does not provide any valuable information.
I also decided to start my images now in servercore instead of IIS since latter only installs WindowsFeature Web-Server and creates ENTRYPOINT for ServiceMonitor.exe. Neither of which is really necessary anyway.
To accomplish this 2 things would need to be changed in base Microsoft image.

  1. Enable IIS to log to ETW (in addition or insted of file logging)
  2. Enable log called Microsoft-IIS-Logging/logs

Step number 1 is accomplished by executing following powershell

Import-module WebAdministration
$splat = @{
    pspath = "MACHINE/WEBROOT/APPHOST"
    filter = "system.applicationHost/sites/siteDefaults/logFile"
    name =  "logTargetW3C"
    value = "File,ETW"
}
Set-WebConfigurationProperty @splat

Step 2 is below

$IISOpsLog = Get-WinEvent -ListLog Microsoft-IIS-Logging/logs
$IISOpsLog.IsEnabled = "true"
$IISOpsLog.SaveChanges()

Both entries are made inside website_config.ps1 file in artifacts directory.

This setup will output ETW events to Microsoft-IIS-Logging/logs which will be repeatadly read in powershell script called entrypoint.ps1 below

$VerbosePreference = "ignore"
$sleep = 5
while ($true)
{
    $datediff = (New-TimeSpan -Seconds $sleep).TotalMilliseconds
    $filter = "*/System/TimeCreated[timediff(@SystemTime) <= $datediff] and *[EventData/Data[@Name='sc-status'] >'400']"
    Get-WinEvent -MaxEvents 10 -FilterXPath $filter -ProviderName "Microsoft-Windows-IIS-Logging" -ErrorAction SilentlyContinue | 
    Select-Object @{Name = "time"; e = {$_.Properties[2].value}}, @{Name = "VERB"; e = {$_.Properties[8].value}}, 
    @{Name = "ClientIP"; e = {$_.Properties[3].value}}, @{Name = "URI"; e = {$_.Properties[9].value}}, 
    @{Name = "Query"; e = {$_.Properties[10].value}}, @{Name = "Status"; e = {$_.Properties[11].value}}, 
    @{Name = "host"; e = {$_.Properties[21].value}} | Format-Table
    Start-Sleep $sleep
}

I restrict number of events returned by query at source based on time since last request as well as only for specific eventcodes which identifies Web Server errors (status codes > 400)

The last step is to put this script into ENTRYPOINT in DOCKERFILE

ENTRYPOINT powershell.exe C:\startup\entrypoint.ps1

Entire code base along with additional files is available on Github page (https://github.com/artisticcheese/IISadmin)
Image on dockerhub is (https://hub.docker.com/r/artisticcheese/iis-admin/)

You can test functionality below

docker run -it artisticcheese/iis-admin

Issue request to non-existent file to local container

invoke-webrequest http://172.30.163.51/asda

You will see output in stdout of container

time     VERB ClientIP     URI   Query Status host         
----     ---- --------     ---   ----- ------ ----         
18:28:08 GET  172.30.160.1 /asda -        404 172.30.163.51

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s