【问题标题】:Powershell Logging within modules and dot sourced scripts模块和点源脚本中的 Powershell 日志记录
【发布时间】:2017-10-19 15:54:57
【问题描述】:

我有几个函数存储在一个 .psm1 文件中,供几个不同的 ps1 脚本使用。我创建了一个日志记录函数(如下所示),我在这些 ps1 脚本中都使用了它。通常,我通过简单地调用类似的东西在脚本中导入模块:

Import-Module $PSScriptRoot\Module_Name.psm1

然后在模块内,我有一个写记录器功能:

Write-Logger -Message "Insert log message here." @logParams

此函数在整个主脚本和模块本身中都使用。喷溅参数@logParams 在我的主 .ps1 文件中定义,并没有显式传递给模块,我想这些变量在导入时隐含在模块的范围内。我有什么作品,但我觉得这不是一个很好的做法。在我的模块中添加 param 块以要求从主 .ps1 脚本显式传递 @logParams 会更好吗?谢谢!

function Write-Logger() {
    [cmdletbinding()]
    Param (
        [Parameter(Mandatory=$true)]
        [string]$Path,
        [Parameter(Mandatory=$true)]
        [string]$Message,
        [Parameter(Mandatory=$false)]
        [string]$FileName = "Scheduled_IDX_Backup_Transcript",
        [switch]$Warning,
        [switch]$Error
    )
    # Creates new log directory if it does not exist
    if (-Not (Test-Path ($path))) {
        New-Item ($path) -type directory | Out-Null
    }

    if ($error) {
        $label = "Error"
    }
    elseif ($warning) {
        $label = "Warning"    
    }
    else {
        $label = "Normal"
    }

    # Mutex allows for writing to single log file from multiple runspaces
    $mutex = new-object System.Threading.Mutex $false,'MutexTest'
    [void]$mutex.WaitOne()
    Write-Host "$(Format-LogTimeStamp) $label`: $message"
    "$(Format-LogTimeStamp) $label`: $message" | Out-file "$path\$fileName.log" -encoding UTF8 -append
    [void]$mutex.ReleaseMutex()
}

【问题讨论】:

  • 您可以使用$PSCommandPath 自动变量,它将从调用脚本返回全名属性。我通常将其解析为基本名称并将其用作日志的名称。这只是在其他模块中使用日志记录功能时的问题,因为日志文件不会匹配。
  • @TheIncorrigible1 谢谢,这是创建日志的好建议。但是,我想我真正想问的是在导入的脚本中合并日志记录的最佳方式是什么?你如何传递日志路径、文件名等?在模块开头声明强制参数以进行日志记录是一种好习惯吗?另外,为了清楚起见,我编辑了原始问题。
  • 在编程语言中记录日志的常用方法是拥有一个日志对象。因此,如果您使用 PowerShell 5+,或者您有 C# 经验,则可以定义一个记录器类对象并利用该对象本身将包含这些详细信息作为属性。
  • @mmartin712 我喜欢你对 Mutex 的使用,我计划将它(即窃取这个想法)合并到我用于通用日志记录的记录器类中(目前,我使用 do/while/sleep 例程) .我使用全局变量,我讨厌将它作为“答案”发布,但我认为它可能对你有用(所以无论如何我都会这样做......)。

标签: powershell logging


【解决方案1】:

我在 ps1 中有这段代码,我将源代码添加到要生成自己的日志的脚本中。 ps1 包含simpleLogger 类以及下面创建全局变量的例程。该脚本可以再次点源,并将全局变量值传递给随后生成的作业以维护单个日志文件。

class simpleLogger
{
    [string]$source
    [string]$target
    [string]$action
    [datetime]$datetime
    hidden [string]$logFile = $global:simpleLog

    simpleLogger()
    {
        $this.datetime = Get-Date
    }

    simpleLogger( [string]$source, [string]$target, [string]$action )
    {
        $this.action = $action
        $this.source = $source
        $this.target = $target
        $this.datetime = Get-Date
    }

    static [simpleLogger] log( [string]$source, [string]$target, [string]$action )
    {
        $newLogger = [simpleLogger]::new( [string]$source, [string]$target, [string]$action )
        do {
            $done = $true
            try {
                $newLogger | export-csv -Path $global:simpleLog -Append -NoTypeInformation
            }
            catch {
                $done = $false
                start-sleep -milliseconds $(get-random -min 1000 -max 10000)
            }
        } until ( $done )
        return $newLogger
    }
}

if( -not $LogSession ){

    $global:logUser = $env:USERNAME
    $global:logDir = $env:TEMP + "\"
    $startLog = (get-date).tostring("MMddyyyyHHmmss")
    $global:LogSessionGuid = (New-Guid)
    $global:simpleLog = $script:logDir+$script:logUser+"-"+$LogSessionGuid+".log"
    [simpleLogger]::new() | export-csv -Path $script:simpleLog -NoTypeInformation
    $global:LogSession = [simpleLogger]::log( $script:logUser, $LogSessionGuid, 'Log init' )

}

【讨论】:

  • 为什么每次需要记录某些东西时都创建一个新对象,而不是使用单个日志对象或类似性质的东西
  • 所以你的意思是,创建一个对象,然后在每次记录的迭代中更新属性?不明白你的意思。我将它用于长时间运行的任务(如 vSphere 迁移、复杂的应用程序安装、操作系统部署等)。我的班级将日志输出流式传输到文件和本地会话的控制台,而不是等待所有任务完成才能看到输出。我还可以从作业中检索输出并将它们添加到同一个流中,因为对象是相同的。在某个时候,我会尝试通过线程安全变量捕获作业输出,但现在我没有充分的理由。
  • 是的,我错过了您示例中的 If 块;没看到滚动条。我以为你每次需要记录一些东西时都在实例化一个新对象,那时你最好使用一个函数
  • 上面的整个代码块都在点源 ps1 文件中。当它被导入会话时,if 语句会创建一个日志会话。导入类后,您记录事件[simpleLogger]::log('source','target','action') 连续的日志条目将自动格式化为相同的表格宽度,因为它们是相同类型的对象。虽然截断发生在控制台中,但写入的日志为 csv 格式且未截断。我冷落任何其他输出并执行 if/else 以保持日志流完整。当您想要奇数 cmdlet 的统一控制台输出时,它工作得很好
猜你喜欢
  • 2018-07-17
  • 2017-07-28
  • 1970-01-01
  • 2016-01-13
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 2017-06-04
  • 1970-01-01
相关资源
最近更新 更多