-
-
Save barsv/85c93b599a763206f47aec150fb41ca0 to your computer and use it in GitHub Desktop.
# all logging settins are here on top | |
$logFile = "log-$(gc env:computername).log" | |
$logLevel = "DEBUG" # ("DEBUG","INFO","WARN","ERROR","FATAL") | |
$logSize = 1mb # 30kb | |
$logCount = 10 | |
# end of settings | |
function Write-Log-Line ($line) { | |
Add-Content $logFile -Value $Line | |
Write-Host $Line | |
} | |
# http://stackoverflow.com/a/38738942 | |
Function Write-Log { | |
[CmdletBinding()] | |
Param( | |
[Parameter(Mandatory=$True)] | |
[string] | |
$Message, | |
[Parameter(Mandatory=$False)] | |
[String] | |
$Level = "DEBUG" | |
) | |
$levels = ("DEBUG","INFO","WARN","ERROR","FATAL") | |
$logLevelPos = [array]::IndexOf($levels, $logLevel) | |
$levelPos = [array]::IndexOf($levels, $Level) | |
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss:fff") | |
if ($logLevelPos -lt 0){ | |
Write-Log-Line "$Stamp ERROR Wrong logLevel configuration [$logLevel]" | |
} | |
if ($levelPos -lt 0){ | |
Write-Log-Line "$Stamp ERROR Wrong log level parameter [$Level]" | |
} | |
# if level parameter is wrong or configuration is wrong I still want to see the | |
# message in log | |
if ($levelPos -lt $logLevelPos -and $levelPos -ge 0 -and $logLevelPos -ge 0){ | |
return | |
} | |
$Line = "$Stamp $Level $Message" | |
Write-Log-Line $Line | |
} | |
# https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Script-to-Roll-a96ec7d4 | |
function Reset-Log | |
{ | |
# function checks to see if file in question is larger than the paramater specified | |
# if it is it will roll a log and delete the oldes log if there are more than x logs. | |
param([string]$fileName, [int64]$filesize = 1mb , [int] $logcount = 5) | |
$logRollStatus = $true | |
if(test-path $filename) | |
{ | |
$file = Get-ChildItem $filename | |
if((($file).length) -ige $filesize) #this starts the log roll | |
{ | |
$fileDir = $file.Directory | |
#this gets the name of the file we started with | |
$fn = $file.name | |
$files = Get-ChildItem $filedir | ?{$_.name -like "$fn*"} | Sort-Object lastwritetime | |
#this gets the fullname of the file we started with | |
$filefullname = $file.fullname | |
#$logcount +=1 #add one to the count as the base file is one more than the count | |
for ($i = ($files.count); $i -gt 0; $i--) | |
{ | |
#[int]$fileNumber = ($f).name.Trim($file.name) #gets the current number of | |
# the file we are on | |
$files = Get-ChildItem $filedir | ?{$_.name -like "$fn*"} | Sort-Object lastwritetime | |
$operatingFile = $files | ?{($_.name).trim($fn) -eq $i} | |
if ($operatingfile) | |
{$operatingFilenumber = ($files | ?{($_.name).trim($fn) -eq $i}).name.trim($fn)} | |
else | |
{$operatingFilenumber = $null} | |
if(($operatingFilenumber -eq $null) -and ($i -ne 1) -and ($i -lt $logcount)) | |
{ | |
$operatingFilenumber = $i | |
$newfilename = "$filefullname.$operatingFilenumber" | |
$operatingFile = $files | ?{($_.name).trim($fn) -eq ($i-1)} | |
write-host "moving to $newfilename" | |
move-item ($operatingFile.FullName) -Destination $newfilename -Force | |
} | |
elseif($i -ge $logcount) | |
{ | |
if($operatingFilenumber -eq $null) | |
{ | |
$operatingFilenumber = $i - 1 | |
$operatingFile = $files | ?{($_.name).trim($fn) -eq $operatingFilenumber} | |
} | |
write-host "deleting " ($operatingFile.FullName) | |
remove-item ($operatingFile.FullName) -Force | |
} | |
elseif($i -eq 1) | |
{ | |
$operatingFilenumber = 1 | |
$newfilename = "$filefullname.$operatingFilenumber" | |
write-host "moving to $newfilename" | |
move-item $filefullname -Destination $newfilename -Force | |
} | |
else | |
{ | |
$operatingFilenumber = $i +1 | |
$newfilename = "$filefullname.$operatingFilenumber" | |
$operatingFile = $files | ?{($_.name).trim($fn) -eq ($i-1)} | |
write-host "moving to $newfilename" | |
move-item ($operatingFile.FullName) -Destination $newfilename -Force | |
} | |
} | |
} | |
else | |
{ $logRollStatus = $false} | |
} | |
else | |
{ | |
$logrollStatus = $false | |
} | |
$LogRollStatus | |
} | |
# to null to avoid output | |
$Null = @( | |
Reset-Log -fileName $logFile -filesize $logSize -logcount $logCount | |
) |
. .\logger.ps1 | |
Write-Log "Started" "INFO" | |
for ($i = 100; $i -gt 0; $i--) | |
{ | |
Write-Log "debug message" | |
Write-Log "debug message2" "DEBUG" | |
Write-Log "info message" "INFO" | |
Write-Log "warn message" "WARN" | |
Write-Log "error message" "ERROR" | |
Write-Log "fatal message" "FATAL" | |
Write-Log "message with wrong level" "WRONG" | |
} |
Thank you very much!
I had to replace line 65:
'$files = Get-ChildItem
with an explicit array declaration:
'$files = @(Get-ChildItem $filedir | ?{$.name -like "$fn*"} | Sort-Object lastwritetime)'
because if only one file exists the script on my machine still wrote in the same file although the filesize exceeded.
I have a need to specify the location of where the log file writes to so I had to modify the Write-Log-Line function slightly. Perhaps it could be of use to some?
# help: https://stackoverflow.com/questions/48425562/powershell-add-content-should-create-path-but-throws-exception-could-not-find-a
function Write-Log-Line ($line) {
$logFile |% {
If (Test-Path -Path $_) { Get-Item $_ }
Else { New-Item -Path $_ -Force }
} | Add-Content -Value $Line
Write-Host $Line
}
Here's a version which keeps the index, and generates names like 'file.1.log', I also simplified the script a lot, though it might not do quite the same advanced index deletion. It now deletes all above $logcount, and then moves the rest into place
editted 2019.09.11 to fix bug if no extension, and if more than 9 maxCount.
# Example Reset-Log -fileName $logfile -maxSize 1mb -maxCount 5
function Roll-logFile
{
#function checks to see if file in question is larger than the paramater specified if it is it will roll a log and delete the oldes log if there are more than x logs.
param([string]$fileName, [int64]$maxSize = 1mb, [int] $maxCount = 9)
$logRollStatus = $true
if(test-path $filename) {
$file = Get-ChildItem $filename
# Start the log-roll if the file is big enough
if((($file).length) -ige $maxSize) {
$fileDir = $file.Directory
$fbase = $file.BaseName
$fext = $file.Extension
$isExtEmpty=($fext.Length -eq 0)
$fn = $file.name #this gets the name of the file we started with
# Write-Host "fbase='$fbase'"
# Write-Host "fext='$fext'"
# Write-Host "isExtEmpty=$isExtEmpty"
function fileBase($file) {
if ($isExtEmpty) {$file.Name} else { $file.BaseName }
}
function refresh-log-files {
# write-host "find logs in dir $filedir matching base '$fbase*' and with extension '$fext'"
Get-ChildItem $filedir | ?{ fileBase($_) -like "$fbase*" -and ($isExtEmpty -or $_.Extension -eq "$fext") } | Sort-Object lastwritetime
}
function getNumberOfFile($theFile) {
$base=fileBase $theFile
Write-Host "$base -eq $fbase" ($base -eq $fbase)
if ($base -eq $fbase) { 0 } else { $base.substring($fbase.length+1) }
}
function fileByIndex($index) {
$files | ?{ (getNumberOfFile $_) -eq $index}
}
function getFileNameByNumber($index) {
"$fbase.$index$fext"
}
refresh-log-files | %{
$num=getNumberOfFile $_
Write-Host "$($_) with number $num"
if ([int]$num -ge $maxCount) {
write-host "Deleting index $_ due to max=$maxCount"
Remove-Item $_
}
}
$files = @(refresh-log-files)
# Now there should be atmost $maxCount files, and the highest number is one less than count, unless there are badly named files, eg non-numbers
for ($i = ($files.count); $i -gt 0; $i--) {
write-host $i
$newfilename = getFileNameByNumber $i
if($i -gt 1) {
$fileToMove = fileByIndex ($i-1)
} else {
$fileToMove = $file
}
if (Test-Path $fileToMove) { # If there are holes in sequence, file by index might not exist. The 'hole' will shift to next number, as files below hole are moved to fill it
write-host "moving '$fileToMove' => '$newfilename'"
# $fileToMove is a System.IO.FileInfo, but $newfilename is a string. Move-Item takes a string, so we need full path
Move-Item ($fileToMove.FullName) -Destination $fileDir\$newfilename -Force
}
}
} else {
$logRollStatus = $false
}
} else {
$logrollStatus = $false
}
$LogRollStatus
}
@arberg
It seems like the roll only works when there are more than 1 file to start. Otherwise I get error "The property 'count' cannot be found on this object." Am I missing something? Sorry I don't have a fix for it at this point (except that I copy/renamed my log so it would have 2) but I'll be working on it as I get time.
@mntlfngs
Its probably because a list was one, and powershell interprets that by removing list unless using @(). I couldn't reproduce the problem, but I have added those, to be safe. I also fixed it so it works without extensions on log-file.
@arberg
Thanks. I got time to tinker and did some changes that made it work for me. Created a fork with my mods .
Just updated my fork with something that I think is working pretty slick now. Quite happy with it.
Thank you for this.
I had an issue with logs rotating correctly, and the fix here resolves it: https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Script-to-Roll-a96ec7d4/view/Discussions#content
Adding in the log rotation call into the Write-Log function takes care of rotating logs live without requiring application
test.ps1
restart.