Анализ текста файла журнала в GO - PullRequest
1 голос
/ 01 октября 2019

Go новичок здесь!

Я пытаюсь собрать программу Go, которая будет анализировать файл журнала и возвращать конкретную информацию в соответствующих строках.

Чтобы привести пример того, что япытаясь достичь, я бы начал с файла журнала, который выглядит следующим образом:

2019-09-30T04:17:02 - REQUEST-A
2019-09-30T04:18:02 - REQUEST-C
2019-09-30T04:19:02 - REQUEST-B
2019-09-30T04:20:02 - REQUEST-A
2019-09-30T04:21:02 - REQUEST-A
2019-09-30T04:22:02 - REQUEST-B

Отсюда я хотел бы извлечь все «REQUEST-A» и либо распечатать время, когда запрос произошел в терминале, либофайл.

Я попытался использовать os.Open и сканер, и я могу использовать scanner.Text, чтобы записать, что он нашел вхождение моей строки, например так:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    request := 0
    f, err := os.Open("request.log")
    if err != nil {
        fmt.Print("There has been an error!: ", err)
    }
    defer f.Close()
    scanner := bufio.NewScanner(f)

    for scanner.Scan() {
        if strings.Contains(scanner.Text(), "REQUEST-A") {
            request = request + 1
        }

        if err := scanner.Err(); err != nil {
        }
        fmt.Println(request)
    }
}

Но яЯ не уверен, как принять это, чтобы использовать его для получения информации, которую я ищу. Обычно я использовал бы Bash для этого, но я думал, что разветвлюсь и посмотрю, смогу ли я использовать Go. Любой совет будет оценен.

Ответы [ 3 ]

2 голосов
/ 01 октября 2019

В Go мы стараемся быть эффективными. Не делайте вещи без необходимости.

Например,

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "os"
)

func main() {
    lines, requestA := 0, 0
    f, err := os.Open("request.log")
    if err != nil {
        fmt.Print("There has been an error!: ", err)
    }
    defer f.Close()

    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        lines++
        // filter request a
        line := scanner.Bytes()
        if len(line) <= 30 || line[30] != 'A' {
            continue
        }
        if !bytes.Equal(line[22:], []byte("REQUEST-A")) {
            continue
        }
        requestA++
        request := string(line)

        // handle request a
        fmt.Println(request)
    }
    if err := scanner.Err(); err != nil {
        fmt.Println(err)
    }
    fmt.Println(lines, requestA)
}

Вывод:

$ go run request.go

2019-09-30T04:17:02 - REQUEST-A
2019-09-30T04:20:02 - REQUEST-A
2019-09-30T04:21:02 - REQUEST-A
6 3

$ cat request.log
2019-09-30T04:17:02 - REQUEST-A
2019-09-30T04:18:02 - REQUEST-C
2019-09-30T04:19:02 - REQUEST-B
2019-09-30T04:20:02 - REQUEST-A
2019-09-30T04:21:02 - REQUEST-A
2019-09-30T04:22:02 - REQUEST-B

Чтобы подчеркнуть важность эффективности (журналы могут быть оченьбольшое), давайте проведем тестирование для решения Маркуса В. Малберга : https://play.golang.org/p/R2D_BeiJvx9.

$ go test log_test.go -bench=. -benchmem
BenchmarkPeterSO-4   21285     56953 ns/op    4128 B/op      2 allocs/op
BenchmarkMarkusM-4     649   1817868 ns/op   84747 B/op   2390 allocs/op

log_test.go:

package main

import (
    "bufio"
    "bytes"
    "regexp"
    "strings"
    "testing"
)

var requestLog = `
2019-09-30T04:17:02 - REQUEST-A
2019-09-30T04:18:02 - REQUEST-C
2019-09-30T04:19:02 - REQUEST-B
2019-09-30T04:20:02 - REQUEST-A
2019-09-30T04:21:02 - REQUEST-A
2019-09-30T04:22:02 - REQUEST-B
`

var benchLog = strings.Repeat(requestLog[1:], 256)

func BenchmarkPeterSO(b *testing.B) {
    for N := 0; N < b.N; N++ {
        scanner := bufio.NewScanner(strings.NewReader(benchLog))
        for scanner.Scan() {
            // filter request a
            line := scanner.Bytes()
            if len(line) <= 30 || line[30] != 'A' {
                continue
            }
            if !bytes.Equal(line[22:], []byte("REQUEST-A")) {
                continue
            }
            request := string(line)
            // handle request a
            _ = request
        }
        if err := scanner.Err(); err != nil {
            b.Fatal(err)
        }
    }
}

func BenchmarkMarkusM(b *testing.B) {
    for N := 0; N < b.N; N++ {
        var re *regexp.Regexp = regexp.MustCompile(`^(\S*) - REQUEST-A$`)
        scanner := bufio.NewScanner(strings.NewReader(benchLog))
        var res []string
        for scanner.Scan() {
            if res = re.FindStringSubmatch(scanner.Text()); len(res) > 0 {
                _ = res[1]
            }
        }
        if err := scanner.Err(); err != nil {
            b.Fatal(err)
        }
    }
}
2 голосов
/ 01 октября 2019

Используйте следующий код для печати поля времени для записей журнала с полем значения «REQUEST-A».

for scanner.Scan() {
    line := scanner.Text()
    if len(line) < 19 {
        continue
    }
    if line[19:] == " - REQUEST-A" {
        fmt.Println(line[:19])
    }
}

Запустите его на игровой площадке Go!

Чтобы записать в файл, перенаправьте стандартный вывод в файл.

Приведенный выше код предполагает, что все после отметки времени равно "- REQUEST-A". Используйте следующее, если «- REQUEST-A» является префиксом для других данных:

const lenTimestamp = 19
for scanner.Scan() {
    line := scanner.Text()
    if len(line) < lenTimestamp {
        continue
    }
    if strings.HasPrefix(line[lenTimestamp:], " - REQUEST-A") {
        fmt.Println(line[:lenTimestamp])
    }
}

Запустите эту версию на игровой площадке .

1 голос
/ 01 октября 2019

Нет необходимости в программе Go, если вы используете Linux или Mac:

$ echo "2019-09-30T04:17:02 - REQUEST-A
2019-09-30T04:18:02 - REQUEST-C
2019-09-30T04:19:02 - REQUEST-B
2019-09-30T04:20:02 - REQUEST-A
2019-09-30T04:21:02 - REQUEST-A
2019-09-30T04:22:02 - REQUEST-B" | awk '/REQUEST-A/{print $1}' | tee request.log
2019-09-30T04:17:02
2019-09-30T04:20:02
2019-09-30T04:21:02

Однако, если вы действительно хотите реализовать это в Go:

package main

import (
    "bufio"
    "fmt"
    "regexp"
    "strings"
)

const input = `
2019-09-30T04:17:02 - REQUEST-A
2019-09-30T04:18:02 - REQUEST-C
2019-09-30T04:19:02 - REQUEST-B
2019-09-30T04:20:02 - REQUEST-A
2019-09-30T04:21:02 - REQUEST-A
2019-09-30T04:22:02 - REQUEST-B
`

var scanner = bufio.NewScanner(strings.NewReader(input))

// Here comes the magic: We create an anonymous group containing all
// non-whitespace characters up to the first blank. Since it is
// a group, we can easily extract it later down the road.
var re *regexp.Regexp = regexp.MustCompile(`^(\S*) - REQUEST-A$`)

func main() {
    var res []string
    for scanner.Scan() {
        // We use re.FindStringSubmatch here, as it actually kills two
        // birds with one stone: We check wether it is REQUEST-A
        // and the anonymous group of the regexp contains what we are looking for.
        if res = re.FindStringSubmatch(scanner.Text()); len(res) > 0 {
            fmt.Println(res[1])
        }
    }
}

Бег на детской площадке

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...