Help us shape the future of Go! Take the 2026 Go Developer Survey

oltgo

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

README

Oltgo Logo

Oltgo — Biblioteca de Telemetria e Observabilidade em Go

O oltgo é uma biblioteca leve, rápida e concorrente projetada para capturar e estruturar logs e rastreamentos (traces) em microsserviços, monólitos ou quaisquer aplicações escritas em Go.


1. Arquitetura Geral

O design segue o princípio 1 Serviço -> 1 Agente, onde cada instância da sua aplicação mantém um único Agent em execução.

+-------------------------------------------------------------+
|                     Aplicação Go                            |
|                                                             |
|   +------------------+           +----------------------+   |
|   |    Collection    | --------> |       Shipping       |   |
|   | (Fila local/Mem) |  (Canal)  | (Worker assíncrono)  |   |
|   +------------------+           +----------------------+   |
+---------------------------------------------|---------------+
                                              v
                                   [ Callback ProcessLog ]
                                   (ex: Gravar em arquivo, 
                                    enviar p/ OpenTelemetry, 
                                    Stripe, ElasticSearch, etc)
Componentes Principais
  1. Agent: Orquestrador central que gerencia o ciclo de vida do pipeline. É inicializado uma única vez na inicialização do serviço.
  2. Collection: Estrutura thread-safe criada para cada transação, requisição ou trace. É responsável por acumular os dados e eventos em memória local e empacotá-los sob o schema unificado ao final da execução.
  3. Shipping: Fila de buffer baseada em Go channels. Ela recebe as instâncias estruturadas prontas do Collection e consome assincronamente os dados para que a aplicação principal nunca sofra atrasos de I/O de escrita.

2. Inicializando o Agente

Para começar, inicialize o Agent definindo os metadados do serviço e um callback opcional de destino para os logs:

package main

import (
	"encoding/json"
	"fmt"
	"github.com/joaooffzz/oltgo"
)

func main() {
	service := oltgo.Service{
		Name:    "payment-gateway",
		Version: "2.1.0",
	}

	// Callback para exportar logs estruturados (ex: saída padrão stdout)
	processLog := func(log oltgo.LogSchema) error {
		bytes, _ := json.Marshal(log)
		fmt.Println(string(bytes))
		return nil
	}

	// Inicializa
	agent := oltgo.NewAgent(service, oltgo.Production, "1", processLog)
	
	// Garante que todos os logs na fila de buffer sejam processados antes da app fechar
	defer agent.Close() 
}

3. Propagação de Contexto via context.Context

O oltgo utiliza o context.Context nativo do Go para carregar e obter a coleção de telemetria através da pilha de execução de funções (call stack), evitando o acoplamento excessivo de código e garantindo segurança concorrente.

Criação e Injeção do Contexto

No início de um fluxo de requisição (por exemplo, um middleware HTTP), você cria a coleção e injeta-a no contexto:

func HandleRequest(w http.ResponseWriter, r *http.Request) {
	// Cria a collection para esta chamada específica
	collection := agent.NewCollection("trace-unique-uuid")
	collection.SetRequestFromHTTP(r, oltgo.ProtoREST, 200)

	// Injeta a collection no contexto
	ctx := oltgo.WithCollection(r.Context(), collection)

	// Propaga o contexto modificado para as funções internas
	checkoutHandler(ctx)

	// Commita os dados para a fila de envio assíncrono
	collection.Commit()
}
Extração e Registro de Eventos na Pilha

Em qualquer sub-função que receba o contexto, você pode extrair a Collection com segurança e registrar eventos:

func executeBusinessLogic(ctx context.Context) {
	// Recupera a coleção. Se não estiver no contexto, retorna nil com segurança
	collection := oltgo.FromContext(ctx)
	if collection == nil {
		return
	}

	// Inicia um evento com cálculo de tempo automático
	event := collection.StartEvent("db_query", oltgo.TypeDatabase, oltgo.SeverityInfo)
	event.WithMessage("Selecionando itens do carrinho")
	
	defer event.End() // Ao finalizar a função, calcula a duração e salva o evento

	// Executa operação de fato...
	if err := queryDB(); err != nil {
		event.AddError("DB_ERROR", err.Error(), nil)
	}
}

4. Eventos Hierárquicos (Árvore de Eventos)

O oltgo suporta o aninhamento automático de eventos em uma estrutura de árvore. Ao usar a função oltgo.StartEvent(ctx, ...), o ID do evento pai é propagado automaticamente pelo context.Context, eliminando a necessidade de vincular manualmente o parent_event_id.

Como funciona
  1. oltgo.StartEvent retorna um novo contexto contendo o ID do evento recém-criado como "evento ativo".
  2. Qualquer chamada subsequente a oltgo.StartEvent usando esse contexto herdará automaticamente o evento anterior como pai.
  3. No Commit(), a lista plana de eventos é reconstruída em uma árvore hierárquica baseada nos parent_event_id.
Exemplo Prático
func checkoutHandler(ctx context.Context) error {
	// Evento raiz — todos os subeventos serão filhos dele
	ctx, mainEvt := oltgo.StartEvent(ctx, "checkout_flow", oltgo.TypeFunction, oltgo.SeverityInfo)
	defer mainEvt.WithMessage("Fluxo de checkout completo").End()

	// Subeventos herdam o pai automaticamente do contexto
	authenticateUser(ctx)
	fetchItems(ctx)

	return nil
}

func authenticateUser(ctx context.Context) {
	// Automaticamente filho de "checkout_flow"
	_, evt := oltgo.StartEvent(ctx, "authenticate_user", oltgo.TypeFunction, oltgo.SeverityInfo)
	defer evt.WithMessage("Usuário autenticado com JWT").End()
}

func fetchItems(ctx context.Context) {
	// Automaticamente filho de "checkout_flow"
	ctx, evt := oltgo.StartEvent(ctx, "fetch_items", oltgo.TypeDatabase, oltgo.SeverityInfo)
	defer evt.WithMessage("Itens carregados").End()

	// Netos: filhos de "fetch_items"
	checkStock(ctx)
}

func checkStock(ctx context.Context) {
	// Automaticamente filho de "fetch_items"
	_, evt := oltgo.StartEvent(ctx, "check_stock", oltgo.TypeDatabase, oltgo.SeverityInfo)
	defer evt.WithMessage("Estoque verificado").End()
}
Saída JSON Resultante

O Commit() produz uma árvore aninhada automaticamente:

{
  "events": [
    {
      "event_id": "evt_001",
      "name": "checkout_flow",
      "events": [
        {
          "event_id": "evt_002",
          "parent_event_id": "evt_001",
          "name": "authenticate_user"
        },
        {
          "event_id": "evt_003",
          "parent_event_id": "evt_001",
          "name": "fetch_items",
          "events": [
            {
              "event_id": "evt_004",
              "parent_event_id": "evt_003",
              "name": "check_stock"
            }
          ]
        }
      ]
    }
  ]
}
Funções Auxiliares de Contexto
Função Descrição
oltgo.StartEvent(ctx, name, type, severity) Cria um evento, herda o pai do contexto e retorna (newCtx, *EventBuilder)
oltgo.WithActiveEvent(ctx, eventID) Associa manualmente um ID de evento ao contexto
oltgo.ActiveEventFromContext(ctx) Recupera o ID do evento ativo do contexto

Nota: A API antiga collection.StartEvent(...) continua funcionando para casos onde o aninhamento não é necessário. Eventos criados por ela não terão parent_event_id e aparecerão como raízes.


5. O Schema de Log Estruturado

Todos os logs commitados são unificados sob uma estrutura padrão e enviados para o callback ProcessLog. A documentação completa dos campos do schema JSON pode ser vista em:

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ActiveEventFromContext added in v0.0.2

func ActiveEventFromContext(ctx context.Context) string

ActiveEventFromContext recupera o ID do evento pai do contexto.

func WithActiveEvent added in v0.0.2

func WithActiveEvent(ctx context.Context, eventID string) context.Context

WithActiveEvent associa um ID de evento ao contexto.

func WithCollection

func WithCollection(ctx context.Context, c *Collection) context.Context

WithCollection injeta uma instância de *Collection no contexto fornecido.

Types

type Actor

type Actor struct {
	ID   string `json:"id"`
	Type string `json:"type"` // USER, SERVICE
	IP   string `json:"ip,omitempty"`
}

type Agent

type Agent struct {
	Service       Service
	Env           Environment
	SchemaVersion string
	Shipping      *Shipping
}

func NewAgent

func NewAgent(service Service, env Environment, schemaVersion string, processLog func(LogSchema) error) *Agent

NewAgent inicializa o Agent de observabilidade. O parâmetro processLog é uma função opcional de callback para processamento dos logs estruturados. Se processLog for nil, os logs serão silenciosamente descartados da memória.

func (*Agent) Close

func (a *Agent) Close()

Close encerra as goroutines do Shipping de forma limpa, garantindo o processamento de logs remanescentes.

func (*Agent) NewCollection

func (a *Agent) NewCollection(tracingID string) *Collection

NewCollection cria uma nova instância de Collection associada a este Agent para rastrear uma nova trace/requisição.

type Collection

type Collection struct {
	// contains filtered or unexported fields
}

func FromContext

func FromContext(ctx context.Context) *Collection

FromContext recupera a instância de *Collection do contexto. Retorna nil se não estiver presente.

func NewCollection

func NewCollection(agent *Agent, tracingID string) *Collection

NewCollection inicializa uma nova Collection vinculada ao Agent.

func (*Collection) AddEvent

func (c *Collection) AddEvent(event Event)

AddEvent insere um evento completo de forma thread-safe.

func (*Collection) Commit

func (c *Collection) Commit()

Commit finaliza a trace, calcula a duração e submete os dados para o Shipping do Agent.

func (*Collection) SetActor

func (c *Collection) SetActor(actor *Actor)

SetActor define informações do ator da requisição.

func (*Collection) SetRequest

func (c *Collection) SetRequest(req *Request)

SetRequest define informações de requisição de forma thread-safe.

func (*Collection) SetRequestFromHTTP

func (c *Collection) SetRequestFromHTTP(r *http.Request, comm CommunicationProto, status int)

SetRequestFromHTTP preenche informações da requisição a partir de um *http.Request nativo.

func (*Collection) StartEvent

func (c *Collection) StartEvent(name string, eventType EventType, severity Severity) *EventBuilder

StartEvent inicia a gravação de um evento. O evento será registrado no Collection chamando End().

type CommunicationProto

type CommunicationProto string
const (
	ProtoREST      CommunicationProto = "REST"
	ProtoGRPC      CommunicationProto = "gRPC"
	ProtoSOAP      CommunicationProto = "SOAP"
	ProtoWebSocket CommunicationProto = "WebSocket"
)

type Environment

type Environment string
const (
	Production  Environment = "production"
	Development Environment = "development"
	Testing     Environment = "testing"
)

type Event

type Event struct {
	EventID       string         `json:"event_id"`
	ParentEventID *string        `json:"parent_event_id"`
	Name          string         `json:"name"`
	Type          EventType      `json:"type"`
	Status        Status         `json:"status"`
	Severity      Severity       `json:"severity"`
	Timestamp     time.Time      `json:"timestamp"`
	DurationMs    int            `json:"duration_ms"`
	Message       string         `json:"message"`
	Metadata      map[string]any `json:"metadata,omitempty"`
	Errors        []EventError   `json:"errors,omitempty"`
	Events        []*Event       `json:"events,omitempty"`
}

type EventBuilder

type EventBuilder struct {
	// contains filtered or unexported fields
}

EventBuilder auxilia desenvolvedores a construírem eventos com cálculo de tempo automático.

func StartEvent added in v0.0.2

func StartEvent(ctx context.Context, name string, eventType EventType, severity Severity) (context.Context, *EventBuilder)

StartEvent inicia a gravação de um evento usando context.Context. O evento herdará o ID do pai automaticamente.

func (*EventBuilder) AddError

func (eb *EventBuilder) AddError(code, message string, stack *string) *EventBuilder

AddError adiciona um erro ocorrido durante a operação do evento, definindo o status do evento como FAILURE.

func (*EventBuilder) End

func (eb *EventBuilder) End()

End calcula o tempo de duração final do evento e o adiciona à Collection.

func (*EventBuilder) WithMessage

func (eb *EventBuilder) WithMessage(msg string) *EventBuilder

WithMessage adiciona uma mensagem explicativa ao evento.

func (*EventBuilder) WithMetadata

func (eb *EventBuilder) WithMetadata(metadata map[string]any) *EventBuilder

WithMetadata injeta dados de contexto adicionais de forma flexível.

func (*EventBuilder) WithParent

func (eb *EventBuilder) WithParent(parentID string) *EventBuilder

WithParent define o ID do evento pai para construir árvores/spans.

type EventError

type EventError struct {
	Code    string  `json:"code"`
	Message string  `json:"message"`
	Stack   *string `json:"stack,omitempty"`
}

type EventType

type EventType string
const (
	TypeFunction        EventType = "FUNCTION"
	TypeDatabase        EventType = "DATABASE"
	TypeExternalService EventType = "EXTERNAL_SERVICE"
	TypeInternalService EventType = "INTERNAL_SERVICE"
)

type LogSchema

type LogSchema struct {
	TracingID     string      `json:"tracing_id"`
	Status        Status      `json:"status"`
	Environment   Environment `json:"environment"`
	SchemaVersion string      `json:"schema_version"`
	Service       Service     `json:"service"`
	Request       *Request    `json:"request,omitempty"`
	Actor         *Actor      `json:"actor,omitempty"`
	Time          TimeInfo    `json:"time"`
	Events        []*Event    `json:"events"`
}

type Request

type Request struct {
	Communication CommunicationProto `json:"communication"`
	Method        string             `json:"method,omitempty"`
	Route         string             `json:"route,omitempty"`
	Status        int                `json:"status"`
	UserAgent     string             `json:"user_agent,omitempty"`
}

type Service

type Service struct {
	ID          *string   `json:"id,omitempty"`
	Name        string    `json:"name"`
	Description *string   `json:"description,omitempty"`
	Version     string    `json:"version"`
	Tags        *[]string `json:"tags,omitempty"`
}

type Severity

type Severity string
const (
	SeverityDebug Severity = "DEBUG"
	SeverityInfo  Severity = "INFO"
	SeverityWarn  Severity = "WARN"
	SeverityError Severity = "ERROR"
	SeverityFatal Severity = "FATAL"
)

type Shipping

type Shipping struct {
	// contains filtered or unexported fields
}

func NewShipping

func NewShipping(bufferSize int, processLog func(LogSchema) error) *Shipping

func (*Shipping) Close

func (s *Shipping) Close()

func (*Shipping) Ship

func (s *Shipping) Ship(log LogSchema)

type Status

type Status string
const (
	StatusSuccess Status = "SUCCESS"
	StatusFailure Status = "FAILURE"
)

type TimeInfo

type TimeInfo struct {
	DurationMs int       `json:"duration_ms"`
	CreatedAt  time.Time `json:"created_at"`
	FinishedAt time.Time `json:"finished_at"`
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL