Dev (Back & Front)ARTIGO

Traceback em Go: Como Explorar a Pilha de Execução

Traceback em Go: Como Explorar a Pilha de Execução
Imagem: Cesar Gimenes

Muitas linguagens de programação fornecem algum tipo de “stack trace” ou “backtrace”. PythonPython56 conteúdosVSCode + Python + Alexa: Desenvolva e teste skills para alexa localmente com pythonDev (Back & Front) · out 2025Dominando decoradores em Python: um guia completo com exemplosDev (Back & Front) · jan 2025Desenvolvimento de software: diferenças entre Python, JavaScript e JavaGestão Dev & TI · nov 2024Ver tudo em Dev (Back & Front) usa o módulo traceback, C no LinuxLinux34 conteúdosKali Linux em um Servidor VPS: como, quando e por que usar?DevSecOps · dez 2024Construindo um Windows Service ou Linux Daemon com Worker Service & .NET Core – Parte 2Dev (Back & Front) · jul 2020Criando uma WebApi utilizando .NET, Linux e VSCodeDev (Back & Front) · ago 2019Ver tudo em DevSecOps oferece a função backtrace() em execinfo.h (não faz parte do padrão do C) e Java inclui Thread.dumpStack() ou e.printStackTrace() para exceções.

Stack Trace em Go

O Go fornece a função runtime.Caller para obter informações sobre a pilha de execução. O exemplo a seguir exibe o arquivo, a linha e a função que chamaram info(). Observe que o argumento 1 passado para runtime.Caller indica que queremos informações sobre a função que chamou info():

go
func info() {
    count := 1
    for {
        pc, filePath, lineNumber, ok := runtime.Caller(count)
        if !ok {
            return
        }

        funcName := runtime.FuncForPC(pc).Name()

        fmt.Printf("%d %s:%d %s\n",
            count,
            filePath,
            lineNumber,
            funcName)

        count++
    }
}

Você pode usar esses dados em um sistema de log para rastrear a origem de um erro. O package log padrão do Go já captura parte dessas informações, mas você pode querer personalizar a saída ou persistir os dados em um banco de dadosBanco de dados134 conteúdosSQL ou NoSQL: eis a questão!!Data · mar 2020Banco de dados: como organizar e dar segurança para milhões de dados de loteriasData · mai 20215 serviços gratuitos na cloud para bancos de dados PostgresData · fev 2025Ver tudo em Data . Em projetos com transações financeiras, por exemplo, é comum registrar cada transação com um ID único end-to-end que acompanha todas as etapas da transação e incluir alguns dados sobre a execução do programa torna muito mais fácil rastrear problemas e fazer auditorias.

Se você quiser imprimir a pilha de execução inteira, utilize um loop que chama runtime.Caller sucessivamente até não haver mais informações disponíveis. O exemplo a seguir ilustra essa abordagem:

go
func traceback() {
    i := 1
    for {
        _, file, line, ok := runtime.Caller(i)
        if !ok {
            break
        }
        fmt.Printf("File: %s, Line: %d\n", file, line)
        i++
    }
}

Assim, você obtém um “stack trace” personalizado em Go. Para mais detalhes sobre runtime.Caller, consulte a documentação oficial em: https://pkg.go.dev/runtime#Caller

runtime.CallersFrames

Outra forma de obter mais detalhes do programa é usar a função runtime.CallersFrames, que retorna um iterador para explorar a pilha de execução. O exemplo a seguir exibe o arquivo, a linha e a função de cada frame da pilha de execução:

go
pcs := make([]uintptr, 10)
n := runtime.Callers(0, pcs)
pcs = pcs[:n]

frames := runtime.CallersFrames(pcs)
for {
    frame, ok := frames.Next()
    if !ok {
        break
    }
    fmt.Printf(
        "%s:%d %s\n",
        frame.File,
        frame.Line,
        frame.Function,
    )
}

Log

Apenas para deixar registrado, você pode muito facilmente fazer com que o log do Go imprima a linha atual e o arquivo em que foi chamado, para isso basta usar o método SetFlags do log na inicialização do seu programa:

go
log.SetFlags(log.LstdFlags | log.Lshortfile)

-trimpath

O Go armazena o caminho completo dos arquivos do seu sistema e das dependências importadas. Se você compilar o programa na sua máquina, o caminho refletirá o diretório local, possivelmente expondo seu nome de usuário e outras informações irrelevantes ou sensíveis. Esses dados podem poluir seus registros de log. Para remover esses caminhos, use o parâmetro -trimpath ao compilar. Assim, o Go reduzirá a exposição de detalhes sensíveis:

bash
go build -trimpath main.go

Conclusão

Obter a pilha de execução em Go é simples e ajuda a rastrear a origem de erros em projetos grandes. Esse recurso é uma ferramenta valiosa para auditoria e diagnóstico. Use runtime.Caller, a função de traceback personalizada ou runtime.CallersFrames para coletar informações detalhadas, e utilize parâmetros como -trimpath para proteger dados sensíveis.

Vídeo com a demonstração do código:

 

Trabalha com tecnologia desde a década de 90. Já atuou na área de educação e participou de projetos de mobilidade de grande volume para laboratórios farmacêuticos. Criou games tanto para PC, como para iOS. Hoje está direcionando seus esforços em plataformas de Sistemas Embarcados, IoT, microservices e cloud computing. É um entusiasta de tecnologias como Golang e Docker.

Ver perfil