Как найти, где в программе Golang происходит мошенническая запись в stderr? - PullRequest
0 голосов
/ 02 марта 2019

У меня довольно большая программа Golang с довольно большим количеством зависимостей.Где-то кто-то пишет мошеннические данные в stderr.

Я хочу выяснить, где происходит эта запись, чтобы я мог удалить ее.

Я знаю, что могу перехватить stderr, используя Dup2 и Pipes, так чтоЯ могу обнаружить запись, как это происходит;но это не позволяет мне получить стек от goroutine, делающего запись.

На других языках я бы установил os.Stderr в пользовательский файл с подключенной функцией Write.Есть ли способ сделать это в Go, о котором я не знаю?Если нет, то какой будет хороший способ узнать, где происходит вызов этого метода?

1 Ответ

0 голосов
/ 03 марта 2019

Вы можете перехватить ведение журнала, указав io.Writer - log.SetOutput .Там вы можете просто проверить, является ли записываемая строка тем, что вам нужно отследить и записать трассировку стека делегированному завернутому модулю записи.

Вот пример игровой площадки: https://play.golang.org/p/2bClt2JBuFs

Обратите внимание, чтополучение текущей трассировки стека не является бесплатным, оно вызывает остановку мира и может существенно замедлить работу вашего приложения.Если у вас есть приложение, которое создает большой объем журналов, я бы порекомендовал ограничить объем отслеживаемых данных (например, трассировать только первое совпадение или N раз в секунду / минуту)

package main

import (
    "fmt"
    "log"
    "os"
    "regexp"
    "runtime/debug"
)

func main() {
    log.SetOutput(NewLogInterceptor(LogInterceptionCheck{Pattern: ".*Some.*", Description: "with 'Some' substring"}))
    f1()
    log.Println("message that is not traced")
}

func f1() {
    log.Println("Some message")
}



type LogInterceptor struct {
    target *os.File
    checks []LogInterceptionCheck
}

type LogInterceptionCheck struct {
    regexp      *regexp.Regexp
    Pattern     string
    Description string
}

func NewLogInterceptor(checks ...LogInterceptionCheck) *LogInterceptor {
    for i := 0; i < len(checks); i++ {
        each := checks[i]
        compiled, e := regexp.Compile(each.Pattern)
        if e != nil {
            log.Fatalf("cannot compile regexpt [%s]: %s", each, e)
        }
        checks[i].regexp = compiled
    }
    return &LogInterceptor{os.Stderr, checks}
}

func (interceptor *LogInterceptor) Write(p []byte) (n int, err error) {
    i, err := interceptor.target.Write(p)
    // use loop because it is faster and generates less garbage compared to for-range loop
    for i := 0; i < len(interceptor.checks); i++ {
        check := interceptor.checks[i]
        if check.regexp.Match(p) {
            _, e := fmt.Fprintf(interceptor.target, ">>>> Printing stacktrace [%s]\n", check.Description)
            if e != nil {
                log.Fatalf("cannot write: %s", e)
            }
            _, e = interceptor.target.Write(debug.Stack())
            if e != nil {
                log.Fatalf("cannot write stacktrace: %s", e)
            }
            break
        }
    }
    return i, err
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...