Skip to content

Commit f05d19e

Browse files
committed
add load win events via wevtutil (parsing txt format)
1 parent f2cd411 commit f05d19e

File tree

1 file changed

+48
-74
lines changed

1 file changed

+48
-74
lines changed

main.go

Lines changed: 48 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"bufio"
55
"encoding/json"
6-
"encoding/xml"
76
"errors"
87
"flag"
98
"fmt"
@@ -888,7 +887,7 @@ func (app *App) selectService(g *gocui.Gui, v *gocui.View) error {
888887
}
889888
// Загружаем журналы выбранной службы, обрезая пробелы в названии
890889
app.loadJournalLogs(strings.TrimSpace(line), true, g)
891-
// Включаем загрузку журнала только при ручном выборе для Windows
890+
// Включаем загрузку журнала (только при ручном выборе для Windows)
892891
app.updateFile = true
893892
// Фиксируем для ручного или автоматического обновления вывода журнала
894893
app.lastWindow = "services"
@@ -910,10 +909,10 @@ func (app *App) loadJournalLogs(serviceName string, newUpdate bool, g *gocui.Gui
910909
switch {
911910
// Читаем журналы Windows
912911
case app.getOS == "windows":
913-
// Отключаем чтение в горутине
914912
if !app.updateFile {
915913
return
916914
}
915+
// Отключаем чтение в горутине
917916
app.updateFile = false
918917
// Извлекаем полное имя события
919918
var eventName string
@@ -1019,82 +1018,57 @@ func (app *App) loadJournalLogs(serviceName string, newUpdate bool, g *gocui.Gui
10191018
// return []byte(fullMessage)
10201019
// }
10211020

1021+
// Функция для чтения и парсинга содержимого события Windows через wevtutil
10221022
func (app *App) loadWinEventLog(eventName string) (output []byte) {
1023-
cmd := exec.Command("powershell", "-Command",
1024-
"chcp 65001 > $null;"+
1025-
"wevtutil qe "+eventName+" /f:RenderedXml /c:5000 -l:en")
1026-
xmlData, _ := cmd.Output()
1027-
decoder := xml.NewDecoder(strings.NewReader(string(xmlData)))
1028-
var eventMessages []string
1029-
var inEvent, inRenderingInfo, inMessage, inLevel, inEventID bool
1030-
var systemTime, level, eventID, message string
1031-
for {
1032-
token, _ := decoder.Token()
1033-
switch elem := token.(type) {
1034-
case xml.StartElement:
1035-
switch elem.Name.Local {
1036-
case "Event":
1037-
inEvent = true
1038-
systemTime, level, eventID, message = "", "", "", ""
1039-
case "TimeCreated":
1040-
if inEvent {
1041-
for _, attr := range elem.Attr {
1042-
if attr.Name.Local == "SystemTime" {
1043-
systemTime = attr.Value
1044-
}
1045-
}
1046-
}
1047-
case "EventID":
1048-
if inEvent {
1049-
inEventID = true
1050-
}
1051-
case "Level":
1052-
if inEvent {
1053-
inLevel = true
1054-
}
1055-
case "RenderingInfo":
1056-
if inEvent {
1057-
inRenderingInfo = true
1058-
}
1059-
case "Message":
1060-
if inRenderingInfo {
1061-
inMessage = true
1023+
cmd := exec.Command("cmd", "/C",
1024+
"chcp 65001 &&"+
1025+
"wevtutil qe "+eventName+" /f:text -l:en")
1026+
eventData, _ := cmd.Output()
1027+
// Декодирование вывода из Windows-1251 в UTF-8
1028+
decoder := charmap.Windows1251.NewDecoder()
1029+
decodeEventData, decodeErr := decoder.Bytes(eventData)
1030+
if decodeErr == nil {
1031+
eventData = decodeEventData
1032+
}
1033+
// Разбиваем вывод на массив
1034+
eventStrings := strings.Split(string(eventData), "Event[")
1035+
var eventMessage []string
1036+
for _, eventString := range eventStrings {
1037+
var dateTime, eventID, level, description string
1038+
// Разбиваем элемент массива на строки
1039+
lines := strings.Split(eventString, "\n")
1040+
// Флаг для обработки последней строки Description с содержимым Message
1041+
isDescription := false
1042+
for _, line := range lines {
1043+
// Удаляем проблемы во всех строках
1044+
trimmedLine := strings.TrimSpace(line)
1045+
switch {
1046+
// Обновляем формат даты
1047+
case strings.HasPrefix(trimmedLine, "Date:"):
1048+
dateTime = strings.ReplaceAll(trimmedLine, "Date: ", "")
1049+
dateTimeParse := strings.Split(dateTime, "T")
1050+
dateParse := strings.Split(dateTimeParse[0], "-")
1051+
timeParse := strings.Split(dateTimeParse[1], ".")
1052+
dateTime = fmt.Sprintf("%s.%s.%s %s", dateParse[2], dateParse[1], dateParse[0], timeParse[0])
1053+
case strings.HasPrefix(trimmedLine, "Event ID:"):
1054+
eventID = strings.ReplaceAll(trimmedLine, "Event ID: ", "")
1055+
case strings.HasPrefix(trimmedLine, "Level:"):
1056+
level = strings.ReplaceAll(trimmedLine, "Level: ", "")
1057+
case strings.HasPrefix(trimmedLine, "Description:"):
1058+
// Фиксируем и пропускаем Description
1059+
isDescription = true
1060+
case isDescription:
1061+
// Добавляем до конца текущего массива все не пустые строки
1062+
if trimmedLine != "" {
1063+
description += "\n" + trimmedLine
10621064
}
10631065
}
1064-
case xml.CharData:
1065-
text := string(elem)
1066-
if inEventID {
1067-
eventID = text
1068-
}
1069-
if inLevel {
1070-
level = text
1071-
}
1072-
if inMessage {
1073-
message = text
1074-
}
1075-
case xml.EndElement:
1076-
switch elem.Name.Local {
1077-
case "Event":
1078-
inEvent = false
1079-
parsedTime, _ := time.Parse(time.RFC3339Nano, systemTime)
1080-
formattedTime := parsedTime.Format("02.01.2006 15:04:05")
1081-
formattedMessage := fmt.Sprintf(
1082-
"%s %s (%s): %s",
1083-
formattedTime, level, eventID, strings.TrimSpace(message),
1084-
)
1085-
eventMessages = append(eventMessages, formattedMessage)
1086-
case "RenderingInfo":
1087-
inRenderingInfo = false
1088-
case "Message":
1089-
inMessage = false
1090-
case "Level":
1091-
inLevel = false
1092-
case "EventID":
1093-
inEventID = false
1094-
}
1066+
}
1067+
if dateTime != "" && eventID != "" && level != "" && description != "" {
1068+
eventMessage = append(eventMessage, fmt.Sprintf("%s %s (%s): %s", dateTime, level, eventID, strings.TrimSpace(description)))
10951069
}
10961070
}
1097-
fullMessage := strings.Join(eventMessages, "\n")
1071+
fullMessage := strings.Join(eventMessage, "\n")
10981072
return []byte(fullMessage)
10991073
}
11001074

0 commit comments

Comments
 (0)