6

我在一台服务器上配置了一个石墨实例,我用它来监视我的环境,遗憾的是它由 linux 和 windows 机器组成。我想监控我的服务器的运行状况,所以我在我的 linux 机器上选择了 collectl,它可以很好地收集系统统计信息。

可悲的是,对于 Windows,似乎没有太多的解决方案可以获取系统统计信息并将其发送到石墨,但我已经设法用 powershell 处理这种情况。我正在使用此处建议的脚本http://josh.behrends.us/2012/07/windows-powershell-graphite-awesome/用于石墨连接以及从我正在使用的计算机中获取指标get-counter 命令,令人惊讶的是,它可以收集大量信息。

我的脚本如下所示:

while (1 -eq 1)
{
$carbonServer = "hostname"
$carbonServerPort = 2003 
$epochtime = [int][double]::Parse((Get-Date -UFormat %s))

$socket = New-Object System.Net.Sockets.TCPClient
$socket.connect($carbonServer, $carbonServerPort)
$stream = $socket.GetStream()
$writer = new-object System.IO.StreamWriter($stream)
#Write out metric to the stream.

$DiskQue =  [int]((get-counter -Counter "\PhysicalDisk(1 e: f:)\Current Disk Queue Length" ).countersamples | select -property cookedvalue).cookedvalue
$BytesReceived = [int]((get-counter -Counter "\Server\Bytes Received/sec" ).countersamples | select -property cookedvalue).cookedvalue
$BytesSent =  [int]((get-counter -Counter "\Server\Bytes Transmitted/sec").countersamples | select -property cookedvalue).cookedvalue
$MemAvail = ((get-counter -Counter "\Memory\Available Bytes").countersamples | select -property cookedvalue).cookedvalue
$MemCommit = ((get-counter -Counter "\Memory\Committed Bytes").countersamples | select -property cookedvalue).cookedvalue
$ReadOp =  [int]((get-counter -Counter "\System\File Read Operations/sec").countersamples | select -property cookedvalue).cookedvalue
$WriteOp = [int]((get-counter -Counter "\System\File Write Operations/sec").countersamples | select -property cookedvalue).cookedvalue

$metric7 = ("hostname.metrics.WriteOp " + $WriteOp + " " + $epochTime+"`n")
$metric7

$writer.WriteLine($metric7)
$writer.Flush() #Flush and write our metrics.
$writer.Close()
$stream.Close()
sleep 5
}

现在,这个脚本乍一看输出了它应该输出的内容。输出具有格式hostname.metrics.name $metric_value $epochTime,但没有绘制图形。它们出现在石墨仪表板中,但它们是空的。我用wireshark检查了发送到石墨服务器的输出。它接缝在 Windows 中,消息附加有 CRLF,而不是在只有 LF 的 linux 中。我\n手动添加了一小段时间,它成功了,但现在它停止了工作。

我的问题是我在传输过程中做错了什么,因为我一直在分析流量,来自被绘制图形的 linux 机器和来自未绘制图形的 Windows 的流量之间的唯一区别是线路终止符。在 linux 中它的 LF(0a) 和 windows 中是 CRLF(0d0a),但我再次尝试从 linux LFCRLF(0a0d0a) 发送,希望石墨服务器只会读取到第一个 LF,而不是解释消息,但我仍然' m 没有得到图表。

此外,当我从 linux 传输时,我只有一条消息,而当我从 powershell 传输时,我有三条消息。从我在 carbon-cache 进程上看到的 strace 中,我有一个带有我想要的消息的 recvfrom 系统调用,而我有另一个是空的和写系统调用(从 powershell 传输时)而不是哟只有一个带有消息和写入的recvfrom(在linux上使用netcat传输时),

4

3 回答 3

3

似乎没有人提供任何建议,因此我采用了另一种方法。我仍然很好奇为什么 Graphite 不解释我发送的消息。这个问题的解决方案是使用 UDP 套接字而不是 TCP 套接字,并将指标发送到 statsd,而后者又将它们发送到 Graphite。这似乎没有任何复杂性,如果您考虑一下,这对您的网络更好,因为它可以最大限度地减少流量(如果您将 statsd 和 Graphite 保持在同一个节点上)。

我发布脚本以防有人遇到我的问题并且他的环境类似于我的。这是脚本

[int] $Port = 8125
$IP = "here is your IP" 
$Address = [system.net.IPAddress]::Parse($IP) 
$End = New-Object System.Net.IPEndPoint $address, $port 
$Saddrf   = [System.Net.Sockets.AddressFamily]::InterNetwork 
$Stype    = [System.Net.Sockets.SocketType]::Dgram 
$Ptype    = [System.Net.Sockets.ProtocolType]::UDP 
$Sock     = New-Object System.Net.Sockets.Socket $saddrf, $stype, $ptype 
$sock.Connect($end) 

function Send_Graphite
{param ($Metric)

$Enc     = [System.Text.Encoding]::ASCII 
$Buffer  = $Enc.GetBytes($Metric) 
$Sent   = $Sock.Send($Buffer) 
"{0} characters sent to: {1} " -f $Sent,$IP 
"Message is:" 
$Metric
sleep 1

}  

while (1 -eq 1)
{
    $DiskQue =  [int]((get-counter -Counter "\PhysicalDisk(1 e: f:)\Current Disk Queue Length" ).countersamples | select -property cookedvalue).cookedvalue
    $BytesReceived = [int]((get-counter -Counter "\Server\Bytes Received/sec" ).countersamples | select -property cookedvalue).cookedvalue
    $BytesSent =  [int]((get-counter -Counter "\Server\Bytes Transmitted/sec").countersamples | select -property cookedvalue).cookedvalue
    $MemAvail = ((get-counter -Counter "\Memory\Available Bytes").countersamples | select -property cookedvalue).cookedvalue
    $MemCommit = ((get-counter -Counter "\Memory\Committed Bytes").countersamples | select -property cookedvalue).cookedvalue
    $ReadOp =  [int]((get-counter -Counter "\System\File Read Operations/sec").countersamples | select -property cookedvalue).cookedvalue
    $WriteOp = [int]((get-counter -Counter "\System\File Write Operations/sec").countersamples | select -property cookedvalue).cookedvalue

    $Message1 = "MAIN.OSmetrics.DiscQueue:"+$DiskQue+"|c"
    $Message2 = "MAIN.OSmetrics.BytesReceived:"+$BytesReceived+"|c"
    $Message3 = "MAIN.OSmetrics.BytesSent:"+$BytesSent+"|c"
    $Message4 = "MAIN.OSmetrics.MemAvail:"+$MemAvail+"|c"
    $Message5 = "MAIN.OSmetrics.MemCommit:"+$MemCommit+"|c"
    $Message6 = "MAIN.OSmetrics.ReadOp:"+$ReadOp+"|c"
    $Message7 = "MAIN.OSmetrics.WriteOp:"+$WriteOp+"|c"

    $Mesages = $Message1, $Message2, $Message3, $Message4, $Message5, $Message6, $Message7
    foreach($Message in $Mesages)
    {
        Send_Graphite $Message 
    }
}

该脚本是可扩展的,您可以监控很多东西,只需运行get-counter -ListSet *您就会看到。我已经使用 TaskScheduler 安装了脚本,您可以通过插入睡眠来控制使用 while 循环的频率。

于 2012-10-30T11:13:10.207 回答
1

我制作了一系列 PowerShell 函数,这些函数对于轻松将指标发送到 Graphite 很有用。您可以配置所有 Windows 性能计数器以及您希望它们多久发送到 Graphite 服务器。完整的源代码在这里:https ://github.com/MattHodge/Graphite-PowerShell-Functions

于 2014-02-08T21:09:03.903 回答
0

我主要想让你知道你并不孤单。我在图表出现时遇到了同样的问题,但数据为空。但是,我能够解决此代码中的 0d0a 与 0a 问题。我也尝试过 UDP,但在我的情况下也没有用。使用这种方法,也许你会对 TCP 有一些运气。从各种来源拼凑出这个。

$dtmUTC = [int][double]::Parse((Get-Date -UFormat %s))
$CR=""
$carbonServer = "host.domain.com"
[int] $carbonServerPort = 2003

[int]$bufSize = 1472  #MTU on this network

$IP = [System.Net.Dns]::GetHostAddresses($carbonServer)
$Address = [system.net.IPAddress]::Parse($IP)
$EndPoint = New-Object System.Net.IPEndPoint $Address, $carbonServerPort
$Saddrf   = [System.Net.Sockets.AddressFamily]::InterNetwork 

#UDP
$Stype    = [System.Net.Sockets.SocketType]::Dgram 
$Ptype    = [System.Net.Sockets.ProtocolType]::UDP 

#TCP
#$Stype    = [System.Net.Sockets.SocketType]::Stream 
#$Ptype    = [System.Net.Sockets.ProtocolType]::TCP 

$Sock     = New-Object System.Net.Sockets.Socket $Saddrf, $Stype, $Ptype 
$Sock.Connect($EndPoint)

function Send_Graphite
{
    param ($thisFile)
    #encoder object
    $Enc = [System.Text.Encoding]::ASCII

    # Read the entire file
    $bytes = [System.IO.File]::ReadAllText($thisFile)

    $begin=0
    $remain=$bytes.Length
    while ( $begin -lt $bytes.Length)
    {

        if ( $remain -lt $bufsize)
        {
            $bufsize = $remain
        }

        $Chunk = $bytes.Substring($begin, $bufsize)
        $Buffer = $Enc.GetBytes($Chunk)
        $rc=$Sock.Send($Buffer)
        sleep 1
        $begin  += $bufsize
        $remain = $remain - $bufsize
    }   
} 

$M=""
foreach ($C in "server1","server2")
{   
    #echo "polling $C ===================="
    ForEach ( $Drives in Get-WmiObject Win32_LogicalDisk -ComputerName $c -Filter "DriveType=3"  )
    {
        ForEach ( $Drive in $Drives )
        {
            $D=$Drive.DeviceID.Replace(":","")
            $SZ=$Drive.Size
            $FS=$Drive.FreeSpace
            $N=$Drive.VolumeName
            $N=$N.Replace(" ","")

            $U=$SZ-$FS
            $S="itinf.stor.$C"

            if ( $FS -eq "" )
            {
                echo "$N FreeSpace was null"
            }
            if ( $N -eq "" )
            {
                $N="default"
                #echo "$N VolumeName was null"
            }
            if ($SZ -eq "")
            {
                echo "$N Size was null"
            }
            $M = $M + $CR
            $CR="`n"
            $M = $M + "$S.$N.Size $SZ $dtmUTC$CR"
            $M = $M + "$S.$N.Free $FS $dtmUTC$CR"
            $M = $M + "$S.$N.Used $U $dtmUTC$CR"
            $M = $M + "$S.$D.Size $SZ $dtmUTC$CR"
            $M = $M + "$S.$D.Free $FS $dtmUTC$CR"
            $M = $M + "$S.$D.Used $U $dtmUTC"
        }
    } 
}

Out-File -NoNewline -FilePath gph.txt -InputObject $M
Send_Graphite gph.txt
sleep .1

if ($Ptype -eq "TCP") { $Sock.Disconnect($EndPoint) }
于 2019-05-31T23:27:20.967 回答