Author Posts

April 22, 2014 at 6:36 am

I have a text log file that I need to monitor for a specific line. I know how to do this. However, when the Rule finds that line, I need information from a different line in the log file that is slightly above it. I am not sure where to begin to accomplish this. There are plenty of examples about how to parse a log file for a single line, but I am not sure how to do it so that it keeps track of all the text above the string I am looking for so I can include it an email.

Here is an example of what the log file will look like (and it will be in this format every time). I need to monitor the log file for the line “No alert email was sent.” and then also include the line “Condition: dest_path (\\Server\Folder) does not exist or is not a directory” in the alert (and maybe some other lines if I can figure out how to do it).

Configuration File config\test210.get at 2013-11-17, 17:12:00

2013-11-17, 17:12:00
Condition: dest_path (\\Server\Folder) does not exist or is not a directory

An error log was created and stored as:
C:/bin/../errors/1117171200004132.log

The global configuration 'SMTPserver' property is not set or is set to an invalid value.
No alert email was sent.
2013-11-17, 17:12:00
Condition: ftp communication problem. Host: rpconnect.redprairie.net

An error log was created and stored as:
C:/live/bin/../errors/1117171200004132.log

The global configuration 'SMTPserver' property is not set or is set to an invalid value.
No alert email was sent.

April 22, 2014 at 6:41 am

So... just as a kind of planning note, I don't think PowerShell is exceptionally well-suited to ongoing "monitoring" activities. The file I/O routines in .NET, for example, aren't the most robust (although they've improved), and PowerShell itself wasn't designed with the idea of it being a long-running monitoring tool. So there's definitely some performance/impact things to consider.

If you look at Select-String, it can do this kind of pattern-based search. It also has a -Context switch, which allows it to return a specified number of lines before/after the "hit." The description for the parameter explains how the context is returned. That's probably where you'd want to start.

April 22, 2014 at 1:08 pm

Hi jacob,

You could try something like this:


$str = @"
2013-11-17, 17:12:01
Condition: dest_path (\\Server\Folder) does not exist or is not a directory

An error log was created and stored as:
C:/bin/../errors/1117171200004132.log

The global configuration 'SMTPserver' property is not set or is set to an invalid value.
No alert email was sent.
2013-11-17, 17:12:02
Condition: ftp communication problem. Host: rpconnect.redprairie.net

An error log was created and stored as:
C:/live/bin/../errors/1117171200004132.log

The global configuration 'SMTPserver' property is not set or is set to an invalid value.
No alert email was sent.
"@
$array = $str -split [System.Environment]::NewLine
$i = 0
$array | foreach{$i++;if($_ -eq "No alert email was sent."){$array[$i-6-1]}}

This implies that the 6th line above your "No alert email was sent." is what you are looking for. Also have to substract 1 since the array is zero based. It is not pretty, however it works 🙂

As a side note, this does not work if you paste the code into a console window. The here-string becomes an one item array in the console, but not in ISE. Apparently the -split is unable to split on newline in the console.

Cheers

Tore

April 23, 2014 at 1:33 am

Hi Jacob.

You could try and make the monitor remember key values from previous lines and react to the triggers you set up.


function Parse-LogFileForErrors {
< # #>
[CmdLetBinding()]
Param(
[parameter(ValueFromPipeline=$true)]
[ValidateScript({Test-Path $_})]
[String]$LogFile
)

BEGIN {
$matchDateString = '^\d{4}-\d{2}-\d{2}, \d{1,2}:\d{1,2}:\d{1,2}'
$matchCondition = '^Condition: (.*)$'
$matchTrigger = 'No alert email was sent.'
$currentDateString = 'startup'
$currentCondition = 'startup'
} #end BEGIN
PROCESS {

$allLines = Get-Content $LogFile
foreach ($line in $allLines) {

switch -Regex ($line) {

$matchDateString { Write-verbose "Found datestring"
$currentDateString = [regex]::Match($line, $matchDateString) }
$matchCondition { Write-Verbose "Found condition"
$currentCondition = [regex]::Match($line, $matchCondition) }
$matchTrigger { Write-Verbose "Found trigger, sending email [triggered: $currentDateString] [$currentCondition]"
# call Send-MailMessage using $currentContidion as body ?
}
default {}

} #end switch

} #end foreach

} #end PROCESS

END {} #end END

}

Parse-LogFileForErrors -logFile d:\logfiles\logfile.log -Verbose

I'm shure there is a more elegant way to do this but this one gives me two "messages" and it is easy to extend.

April 23, 2014 at 11:48 am

Jacob sends his thanks for the responses – he's having some trouble posting a reply.