diff --git a/LICENCE b/LICENSE similarity index 100% rename from LICENCE rename to LICENSE diff --git a/README.md b/README.md index 27b990b..f0bca72 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,31 @@ # Windows Event Log Integration -* Pipes Windows PowerShell `Get-EventLog` entries to Insights. -* LogName configurable through Infrastructure definition and config files. +* Pipes Windows PowerShell `Get-EventLog` entries to New Relic Logs. +* Configurable through Infrastructure config file. -## Disclaimer -New Relic has open-sourced this integration to enable monitoring of this technology. This integration is provided AS-IS WITHOUT WARRANTY OR SUPPORT, although you can report issues and contribute to this integration via GitHub. Support for this integration is available with an [Expert Services subscription](https://newrelic.com/expertservices). +![screenshot](./docs/windows-event-log.png) + +Information about each run (number of Windows events posted, etc) are added to Insights as events of type winEventLogAgt. + +This integration requires New Relic Infrastructure 1.8.0 or newer. ## Instructions -1. Copy .zip from Releases to host -2. Unzip files -3. Copy `infra-windows-logs-config.yml` to `C:\Program Files\New Relic\newrelic-infra\integrations.d` +1. Copy .zip from Releases to host you'll be running on. + +2. Unzip files. + +3. Copy `newrelic-win-eventlog-config.yml` to `C:\Program Files\New Relic\newrelic-infra\integrations.d` + 4. Copy the remaining files to `C:\Program Files\New Relic\newrelic-infra\custom-integrations` - 1. `infra-windows-logs-definition.yml` - 2. `infra-windows-logs.bat` - 3. `infra-windows-logs.ps1` -5. Run: `net stop newrelic-infra` -6. Run: `net start newrelic-infra` -Events are sent to the `Windows Event Logs` Event Type + a. `win-eventlogs-logs.bat` + b. `win-eventlogs-logs.ps1` + +5. Open newrelic-win-eventlog-config.yml with your favorite editor. + +6. By default, the integration collects all Application and System event log entries. Each log type has its own stanza. At minimum, you need to edit the file to add your New Relic license key. See the template file for complete docs. + +7. Run: `net stop newrelic-infra` -![screenshot](./docs/windows-events-log.jpg) +8. Run: `net start newrelic-infra` diff --git a/docs/windows-event-log.png b/docs/windows-event-log.png new file mode 100644 index 0000000..9c76c7c Binary files /dev/null and b/docs/windows-event-log.png differ diff --git a/docs/windows-events-log.jpg b/docs/windows-events-log.jpg deleted file mode 100644 index 384e7a8..0000000 Binary files a/docs/windows-events-log.jpg and /dev/null differ diff --git a/etc/windows-events-log.png b/etc/windows-events-log.png new file mode 100644 index 0000000..f3c8495 Binary files /dev/null and b/etc/windows-events-log.png differ diff --git a/infra-windows-logs-config.yml b/infra-windows-logs-config.yml deleted file mode 100644 index dfafd19..0000000 --- a/infra-windows-logs-config.yml +++ /dev/null @@ -1,7 +0,0 @@ -integration_name: com.newrelic.windows.eventlog - -instances: - - name: eventlog-system - command: system - - name: eventlog-application - command: application diff --git a/infra-windows-logs-definition.yml b/infra-windows-logs-definition.yml deleted file mode 100644 index ba1b3d1..0000000 --- a/infra-windows-logs-definition.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: com.newrelic.windows.eventlog -protocol_version: 1 -description: On-Host Integration for Windows Event Logs - -commands: - application: - command: - - .\infra-windows-logs.bat - - Application - interval: 30 - system: - command: - - .\infra-windows-logs.bat - - System - interval: 30 diff --git a/infra-windows-logs.bat b/infra-windows-logs.bat deleted file mode 100644 index a17462a..0000000 --- a/infra-windows-logs.bat +++ /dev/null @@ -1,9 +0,0 @@ -@ECHO OFF -set logName=%1 -set eventIds=%2 - -IF DEFINED eventIds ( - powershell.exe -ExecutionPolicy Unrestricted -file infra-windows-logs.ps1 -LogName %logName% -EventIds %eventIds% -) ELSE ( - powershell.exe -ExecutionPolicy Unrestricted -file infra-windows-logs.ps1 -LogName %logName% -) diff --git a/infra-windows-logs.ps1 b/infra-windows-logs.ps1 deleted file mode 100644 index ceb02f6..0000000 --- a/infra-windows-logs.ps1 +++ /dev/null @@ -1,110 +0,0 @@ -### -# The following command is required for testing: -# -# [System.Diagnostics.EventLog]::CreateEventSource("New Relic","Application") -### - - -### -# Parameters (a.k.a. Command Line Arguments) -# Usage: -LogName "LogName" -EventIds 4608:4609:4946 -# -LogName The name of the event log to gather events from. Ex: System, Appication, etc. (Required) -# -EventIds An optional, colon delimited, list of event ids to gather. -### - -param ( - [string]$LogName=$(throw "-LogName is mandatory"), - [string]$EventIds -) - -### -# Logic to handle getting new log entries by saving current date to file -# to use as -After argument of Get-Date in next pull. On first run we use current date. -# On subsequent runs it will use last date written to file. -# -# Uses LogName param to create timestamp for each LogName -### - -$LAST_PULL_TIMESTAMP_FILE = "./last-pull-timestamp-$LogName.txt" - - -### -# If timestamp file exists, use it; otherwise, -# set timestamp to 15 minutes ago to pull some data on -# first run. -### - -if (Test-Path $LAST_PULL_TIMESTAMP_FILE -PathType Leaf) { - - $timestamp = Get-Content -Path $LAST_PULL_TIMESTAMP_FILE -Encoding String | Out-String - $timestamp = [DateTime] $timestamp.ToString() - -} else{ - - $timestamp = (Get-Date).AddMinutes(-240) - -} - -### -# Write timestamp to file to pull on next run. -### -Set-Content -Path $LAST_PULL_TIMESTAMP_FILE -Value (Get-Date -Format o) - -### -# Pull events using -After param with timestamp -### -$events = Get-EventLog -LogName $LogName -After $timestamp - -### -# If event ids were given, filter to keep only the events having an id in our event id list. -### -if ($EventIds) { - $eventIdStrings = $EventIds.Split(":") - $eventIdNums = @() - foreach ($eventId in $eventIdStrings) { - $eventIdNums += [convert]::ToInt32($eventId) - } - - # Iterate over the events and copy only those we want to keep into the filteredEvents. - $filteredEvents = @() - foreach ($event in $events) { - if (-Not ($eventIdNums -Contains $event.EventID)) { - continue - } - $filteredEvents += $event - } - $events = $filteredEvents -} - -### -# Add required 'event_type' to objects from Get-EventLog. -# Add optional 'log_name' value to object. -### -$events.ForEach({ - Add-Member -NotePropertyName 'event_type' -NotePropertyValue 'Windows Event Logs' -InputObject $_ - Add-Member -NotePropertyName 'log_name' -NotePropertyValue $LogName -InputObject $_ - -}); - -### -# Create hash table in required format for Infrastructure, populated -# with event object log data and pipe to ConvertTo-Json with -# -Compress argument required in order for Infrastructure to consume. -### -$payload = @{ - name = "com.newrelic.windows.eventlog" - integration_version = "0.1.0" - protocol_version = 1 - metrics = @($events) - inventory = @{} - events = @() -} | ConvertTo-Json -Compress - - -### -# Output json string created above with regex to normalize date strings -# post json string conversion. Alternatively, you could create a -# new -NotePropertyName with the proper date string and remove -# the original object property. -### -Write-Output ($payload -replace '"\\\/Date\((\d+)\)\\\/\"' ,'$1') diff --git a/newrelic-win-eventlog-config.template.yml b/newrelic-win-eventlog-config.template.yml new file mode 100644 index 0000000..94e5b89 --- /dev/null +++ b/newrelic-win-eventlog-config.template.yml @@ -0,0 +1,36 @@ +# This is a template config file for v2.1 of New Relic's Windows event log Infrastructure integration. +# +# By default, we collect all entries from the Application and System log. To add another log type, +# copy an entire -name stanza, change the name so it's unique, and then set the LOGNAME property to your log's name (i.e. Security, Setup, etc) +# +# Filtering uses OR logic. We first filter out the requested levels (Information, Warning) and then the event IDs. +# If you use both filters simultaneously, be sure that you understand this interaction. For example, you cannot filter out +# all Information events except event ID 7036 (which is always level Info). + +integrations: + - name: nr-win-eventlogs-app + exec: + - C:\Program Files\New Relic\newrelic-infra\custom-integrations\win-eventlogs.bat + env: + # The name of the log to be sent (i.e. Application, System, etc) - this is REQUIRED. + LOGNAME: Application + # Your New Relic license key - this is REQUIRED. + NRLICENSEKEY: (YourNRLicenseKeyHere) + # Either none or a comma delimited list of the log levels to be filtered out and not sent to NR. (i.e. Information,Warning) + # Do not leave this blank. + EXCLLEVEL: none + # Either none or a comma delimited list of the event IDs to be filtered out and not sent to NR. (i.e. 123,456) + # Do not leave this blank. + EXCLEVENTID: none + working_dir: C:\Program Files\New Relic\newrelic-infra\custom-integrations\ + interval: 300s + - name: nr-win-eventlogs-sys + exec: + - C:\Program Files\New Relic\newrelic-infra\custom-integrations\win-eventlogs.bat + env: + LOGNAME: System + NRLICENSEKEY: (YourNRLicenseKeyHere) + EXCLLEVEL: none + EXCLEVENTID: none + working_dir: C:\Program Files\New Relic\newrelic-infra\custom-integrations\ + interval: 300s diff --git a/newrelic-win-eventlog-config.yml b/newrelic-win-eventlog-config.yml new file mode 100644 index 0000000..b3ca855 --- /dev/null +++ b/newrelic-win-eventlog-config.yml @@ -0,0 +1,21 @@ +integrations: + - name: nr-win-eventlogs-app + exec: + - C:\Program Files\New Relic\newrelic-infra\custom-integrations\win-eventlogs.bat + env: + LOGNAME: Application + NRLICENSEKEY: (YourNRLicenseKeyHere) + EXCLLEVEL: none + EXCLEVENTID: none + working_dir: C:\Program Files\New Relic\newrelic-infra\custom-integrations\ + interval: 300s + - name: nr-win-eventlogs-sys + exec: + - C:\Program Files\New Relic\newrelic-infra\custom-integrations\win-eventlogs.bat + env: + LOGNAME: System + NRLICENSEKEY: (YourNRLicenseKeyHere) + EXCLLEVEL: none + EXCLEVENTID: none + working_dir: C:\Program Files\New Relic\newrelic-infra\custom-integrations\ + interval: 300s diff --git a/win-eventlogs.bat b/win-eventlogs.bat new file mode 100644 index 0000000..960e433 --- /dev/null +++ b/win-eventlogs.bat @@ -0,0 +1,2 @@ +@ECHO OFF +powershell.exe -ExecutionPolicy Unrestricted -file win-eventlogs.ps1 -LogName %logname% -ExclLevel %excllevel% -ExclEventID %excleventid% -nrLicenseKey %nrlicensekey% diff --git a/win-eventlogs.ps1 b/win-eventlogs.ps1 new file mode 100644 index 0000000..c082c93 --- /dev/null +++ b/win-eventlogs.ps1 @@ -0,0 +1,125 @@ +### +# This PowerShell script grabs the Windows event logs and posts them to New Relic Logs. +# v2.1 - Updated to provide filtering out of event type (i.e. Verbose, Informational, Warning, Error, Critical) and EventID. +# +# The following command is required for testing: +# +# [System.Diagnostics.EventLog]::CreateEventSource("New Relic","Application") +### + +### +# Parameters (a.k.a. Command Line Arguments) +# Usage: -LogName "LogName" +# Required - throw if missing +### + +param ( + [string]$LogName=$(throw "-LogName is mandatory"), + [string]$nrLicenseKey=$(throw "-nrLicenseKey is mandatory"), + [string[]]$ExclLevel = "", + [string[]]$ExclEventID = "" +) + +# App Version (so we know if someone's running an older release of this integration) +$appVersion = "2.1" + +# New Relic Logs endpoint +$nrLogEndpoint = "https://log-api.newrelic.com/log/v1" + +### +# Logic to handle getting new log entries by saving current date to file +# to use as -After argument of Get-Date in next pull. On first run we use current date. +# On subsequent runs it will use last date written to file. +# +# Uses LogName param to create timestamp for each LogName +### + +$LAST_PULL_TIMESTAMP_FILE = "./last-pull-timestamp-$LogName.txt" + + +### +# If timestamp file exists, use it; otherwise, +# set timestamp to 15 minutes ago to pull some data on +# first run. +### + +if(Test-Path $LAST_PULL_TIMESTAMP_FILE -PathType Leaf) { + + $timestamp = Get-Content -Path $LAST_PULL_TIMESTAMP_FILE -Encoding String | Out-String; + $timestamp = [DateTime] $timestamp.ToString(); + +}else{ + + $timestamp = (Get-Date).AddMinutes(-15); + +} + +### +# Write current timestamp to file to pull on next run. +### +Set-Content -Path $LAST_PULL_TIMESTAMP_FILE -Value (Get-Date -Format o) + +### +# Pull events using -After param with timestamp. Use PowerShell Calculated Properties to rename some properties to expected values. +# For some reason, the -or operator doesn't work as expected in a single Where-Object cmdlet, so I had to use two. +### +$events = Get-EventLog -LogName $LogName -After $timestamp | Where-Object {$_.EntryType -notin $ExclLevel} | Where-Object {$_.EventID -notin $ExclEventID} | Select-Object @{Name = "hostname"; Expression = {$_.MachineName}}, ` + @{Name = "message"; Expression = {$_.Message}}, ` + @{Name = "level"; Expression = {$_.EntryType}}, ` + TimeGenerated, Category, EventID, Source, UserName; + +### +# Add required 'event_type' to objects from Get-EventLog. +# Add optional 'log_name' value to object. +### +$events | ForEach({ + + Add-Member -NotePropertyName 'event_type' -NotePropertyValue 'Windows Event Logs' -InputObject $_; + Add-Member -NotePropertyName 'log_name' -NotePropertyValue $LogName -InputObject $_; + + # Recast Level (Informational, Warning, Critical) from an enum to a string so we see it in the UI. + $_.Level = [string]$_.Level; + +}); + +### +# Create hash table in required format for Logs, populated +# with event object log data and pipe to ConvertTo-Json with +# -Compress argument required in order for Logs to consume. +### +$logPayload = @($events) | ConvertTo-Json -Compress + +## +# Output json string created above with regex to normalize date strings +# post json string conversion.. +# +# For some reason, PowerShell won't let me rename the TimeGenerated event property in the event object, so we have to resort +# to using a regex here. +### +$logPayload = Write-Output ($logPayload -replace '"\\\/Date\((\d+)\)\\\/\"' ,'$1') +$logPayload = Write-Output ($logPayload -replace 'TimeGenerated', 'timestamp') +Write-Output $logPayload + +# Set the headers expected by Logs +$headers = @{'Content-Type' = 'application/json'; 'X-License-Key' = $nrLicenseKey} + +# Do the post to the Logs API +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$response = Invoke-WebRequest $nrLogEndpoint -Headers $headers -Method 'POST' -Body $logPayload + +# +# Create a structure readable by NR Infra with metadata about this transaction for meta-Logging / debugging purposes +# +$nrMetaData = @{'event_type' = 'winEventLogAgt'; 'appVersion' = $appVersion; 'excludedEvents' = $ExclEventID; 'excludedLevels' = $ExclLevel; 'hostTime' = Get-Date -UFormat %s -Millisecond 0; 'pullAfter' = $timestamp.ToString(); 'logName' = $LogName; 'eventCount' = $events.Count; 'nrLogsResponse' = $response.StatusCode} + +$metaPayload = @{ + name = "com.newrelic.windows.eventlog" + integration_version = "0.1.0" + protocol_version = 1 + metrics = @($nrMetaData) + inventory = @{} + events = @() +} | ConvertTo-Json -Compress +Write-Output $metaPayload + +#Write-Output "Response" $response.StatusCode