En esta oportunidad tuve la necesidad de monitorear un viejo servidor de dominio Windows utilizando Grafana. Al igual que la anterior oportunidad en que tuve que monitorear un vetusto Informix, por cuestiones de compatibilidad, lo mejor fue recolectar estadísticas utilizando directamente un script PowerShell y enviarlas a InfluxDB con curl. Sin recurrir a herrramientas como collectd o Telegraf (no disponibles para sistemas Windows de 32 bits).



El script se encarga de recolectar estadísticas de uso de CPU, memoria y disco, además de carga, tráfico de red y conexiones TCP.

Antes de comenzar, es necesario instalar PowerShell (en caso de que el sistema no disponga de dicha herramienta) y curl.

El script que implementa la recolección de datos de monitoreo es el siguiente:

$InfluxdbUser = "windowsito"
$InfluxdbPass = "1234"
$InfluxdbUrl = "http://192.168.13.62:8086/write?db=collectd"
$Hostname = "ds.linuxito.com"

$Query = ""

# Obtener información del sistema
$OperatingSystem = Get-WmiObject -Class WIN32_OperatingSystem

# Obtener uso de memoria
$MemoryUsed = ($OperatingSystem.TotalVisibleMemorySize - $OperatingSystem.FreePhysicalMemory)*100 / $OperatingSystem.TotalVisibleMemorySize
$MemoryFree = 100 - $MemoryUsed

$Tag = "memory_value,host=$Hostname,type=memory"
$Query = "$Tag,type_instance=used value=$MemoryUsed"
$Query += "`n$Tag,type_instance=free value=$MemoryFree"

# Carga
$Load = (Get-WmiObject win32_processor | Measure-Object -property LoadPercentage -Average | findstr Average).split(":")[1].trim() -replace ",", "."

$Tag = "load_value,host=$Hostname,type=load"
$Query += "`n$Tag value=$Load"

# Uso de CPU por proceso (top 20)
#$CPUUsage = Get-Counter -ComputerName localhost '\Process(*)\% Processor Time' | Select-Object -ExpandProperty countersamples | Select-Object -Property instancename, cookedvalue | Sort-Object -Property cookedvalue -Descending | Select-Object -First 20 | ft InstanceName,@{L='CPU';E={($_.Cookedvalue/100).toString('P')}} -AutoSize

$CPUUsage = ""

try {
    $CPU_total = Get-Counter -ComputerName localhost '\Process(_total)\% Processor Time' | Select-Object -ExpandProperty countersamples | Select-Object -Property instancename, cookedvalue | ft -AutoSize | findstr _total
    $CPUidle = Get-Counter -ComputerName localhost '\Process(idle)\% Processor Time' | Select-Object -ExpandProperty countersamples | Select-Object -Property instancename, cookedvalue | ft -AutoSize| findstr idle
}
catch [Exception] {
    # do nothing
}

# Obtener uso total de CPU
$CPU_total = ((echo $CPU_total) -replace '\s+', ' ').split(" ")[1]
$CPUidle = ((echo $CPUidle) -replace '\s+', ' ').split(" ")[1]
$CPU_total = (echo $CPU_total) -replace ',', '.'
$CPUidle = (echo $CPUidle) -replace ',', '.'
$CPUused = (([single]$CPU_total - [single]$CPUidle)/[single]$CPU_total)*100

$Tag = "cpu_value,host=$Hostname,type=percent"
$Query += "`n$Tag,type_instance=used value=$CPUused"
$Query += "`n$Tag,type_instance=idle value=$CPUidle"
$Query += "`n$Tag,type_instance=total value=$CPU_total"

# Estadísticas de E/S
$DiskWriteBytesPersec = (Get-WmiObject Win32_PerfRawData_PerfDisk_PhysicalDisk | Where-Object { $_.Name -like "0*"}).DiskWriteBytesPersec
$DiskReadBytesPersec = (Get-WmiObject Win32_PerfRawData_PerfDisk_PhysicalDisk | Where-Object { $_.Name -like "0*"}).DiskReadBytesPersec
$Tag = "disk_value,host=$Hostname"
$Query += "`n$Tag,type_instance=write_bytes value=$DiskWriteBytesPersec"
$Query += "`n$Tag,type_instance=read_bytes value=$DiskReadBytesPersec"

# Estadísticas de red por protocolo
# netstat -s
# netstat -t

$Netstats = netstat -s
$Netstatt = netstat -nt

$PacketsReceived = ((echo $Netstats | Select-String 'Packets Received') -replace '\s+', '').split("=")[1]
$SegmentsReceived = ((echo $Netstats | Select-String 'Segments Received') -replace '\s+', '').split("=")[1]
$SegmentsSent = ((echo $Netstats | Select-String 'Segments Sent') -replace '\s+', '').split("=")[1]
$SegmentsRetransmitted = ((echo $Netstats | Select-String 'Segments Retransmitted') -replace '\s+', '').split("=")[1]
$ActiveOpens = ((echo $Netstats | Select-String 'Active Opens') -replace '\s+', '').split("=")[1]
$PassiveOpens = ((echo $Netstats | Select-String 'Passive Opens') -replace '\s+', '').split("=")[1]
$FailedConnectionAttempts = ((echo $Netstats | Select-String 'Failed Connection Attempts') -replace '\s+', '').split("=")[1]
$ResetConnections = ((echo $Netstats | Select-String 'Reset Connections') -replace '\s+', '').split("=")[1]
$DatagramsReceived = ((echo $Netstats | Select-String 'Datagrams Received') -replace '\s+', '').split("=")[1]
$DatagramsSent = ((echo $Netstats | Select-String 'Datagrams Sent') -replace '\s+', '').split("=")[1]

$Tag = "network_value,host=$Hostname"
$Query += "`n$Tag,type=PacketsReceived value=$PacketsReceived"
$Query += "`n$Tag,type=SegmentsReceived value=$SegmentsReceived"
$Query += "`n$Tag,type=SegmentsSent value=$SegmentsSent"
$Query += "`n$Tag,type=SegmentsRetransmitted value=$SegmentsRetransmitted"
$Query += "`n$Tag,type=ActiveOpens value=$ActiveOpens"
$Query += "`n$Tag,type=PassiveOpens value=$PassiveOpens"
$Query += "`n$Tag,type=FailedConnectionAttempts value=$FailedConnectionAttempts"
$Query += "`n$Tag,type=ResetConnections value=$ResetConnections"
$Query += "`n$Tag,type=DatagramsReceived value=$DatagramsReceived"
$Query += "`n$Tag,type=DatagramsSent value=$DatagramsSent"

$NetstatESTABLISHED = (echo $Netstatt | Select-String 'ESTABLISHED' | Measure-Object -line).Lines
$NetstatTIME_WAIT = (echo $Netstatt | Select-String 'TIME_WAIT' | Measure-Object -line).Lines
$NetstatFIN_WAIT = (echo $Netstatt | Select-String 'FIN_WAIT' | Measure-Object -line).Lines
$NetstatCLOSE_WAIT = (echo $Netstatt | Select-String 'CLOSE_WAIT' | Measure-Object -line).Lines

$Tag = "network_value,host=$Hostname,type=tcp"
$Query += "`n$Tag,type_instance=ESTABLISHED value=$NetstatESTABLISHED"
$Query += "`n$Tag,type_instance=TIME_WAIT value=$NetstatTIME_WAIT"
$Query += "`n$Tag,type_instance=FIN_WAIT value=$NetstatFIN_WAIT"
$Query += "`n$Tag,type_instance=CLOSE_WAIT value=$NetstatCLOSE_WAIT"

C:\curl\bin\curl.exe --silent -u $InfluxdbUser`:$InfluxdbPass -i -XPOST "$InfluxdbUrl" --data-binary "$Query" > $null

Es necesario crear una cuenta de usuario para autenticarse en la API HTTP de InfluxDB y configurar las credenciales en las variables $InfluxdbUser y $InfluxdbPass. Al igual que la URL de acceso a InfluxDB y el nombre de host.

Notar que, en la última línea del script, se utiliza una ruta absoluta al binario curl.exe. Ajustar según corresponda.

Por último es necesario configurar la tarea programada para que el script sea ejecutado periódicamente cada 1, 2 o 5 minutos.

Desde el menú de inicio de Windows abrir "Control Panel > Scheduled Tasks". Hacer clic derecho y agregar una nueva tarea desde "New > Scheduled Task". Establecer un nombre y abrir sus propiedades haciendo doble clic sobre la nueva tarea.

Para ejecutar el script, se pasa como parámetro al binario de PowerShell:

C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe C:\scripts\grafana.ps1

En la pestaña "Schedule", si se desea ejecutar 24/7 cada x cantidad de minutos, es necesario establecer la periodicidad diaria:

Esto hace que la tarea se ejecute sólo una vez al día.

Luego, acceder a la configuración avanzada y repetir la tarea cada, por ejemplo, 2 minutos:

Finalmente, la duración debe ser igual a 23 horas y 58 minutos. Cosas locas de Windows, algo que en cron es tan simple de configurar como definir la periodicidad */2 * * * *.

Ahora resta crear un nuevo dashboard:

Consultas InfluxQL de ejemplo (% de uso de CPU y datagramas recibidos):

SELECT mean("value") FROM "cpu_value" WHERE ("host" = 'ds.linuxito.com' AND "type_instance" = 'used') AND $timeFilter GROUP BY time($__interval) fill(none)
SELECT derivative(mean("value"), 10s) FROM "network_value" WHERE ("host" = 'ds.linuxito.com' AND "type" = 'DatagramsReceived') AND $timeFilter GROUP BY time($__interval) fill(none)

Referencias


Tal vez pueda interesarte


Compartí este artículo