reporter

package module
v2.0.4 Latest Latest
Warning

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

Go to latest
Published: Jun 9, 2026 License: MIT Imports: 11 Imported by: 0

README

Reporter

reporter is a small Go package for turning ordinary errors into structured error reports. It captures the caller file path, line number, function name, error description, raw error text, service name, environment, and timestamp. The same structured payload can be published to Kafka or a custom publisher so another service can forward the alert to Telegram or any other notification channel.

What It Produces

Each wrapped error is represented as CustomError:

{
  "timestamp": "2026-06-04 14:35:12",
  "environment": "production",
  "service": "payment-service",
  "severity": "info",
  "error_type": "DATABASE_CONSTRAINT",
  "description": "Failed to save data because of a duplicate data conflict",
  "raw_error": "duplicate key value violates unique constraint",
  "file": "service/order.go",
  "line": 42,
  "function": "service.CreateOrder"
}

In non-production environments, err.Error() returns a colored terminal-friendly message. In production, err.Error() returns JSON.

Publishing does not use err.Error(). Publishers receive the structured CustomError value, and the built-in Kafka publisher always sends JSON. That means AppEnv: "development" still prints a colored local message, but Kafka receives JSON like this:

{
  "timestamp": "2026-06-04 14:35:12",
  "environment": "development",
  "service": "payment-service",
  "severity": "info",
  "error_type": "DATABASE_CONSTRAINT",
  "description": "Failed to save data because of a duplicate data conflict",
  "raw_error": "duplicate key value violates unique constraint",
  "file": "service/order.go",
  "line": 42,
  "function": "service.CreateOrder"
}

AutoWrap and Wrap print the formatted report automatically when they create a CustomError. Do not print the returned error again unless you intentionally want duplicate output.

Configuration

Call reporter.Init(config) once during service startup. Configuration is passed explicitly through reporter.Config, so this package does not read environment variables directly.

reporter.Init(reporter.Config{
    AppName:          "payment-service",
    AppEnv:           "development",
    EnablePublishing: false,
})
defer reporter.Close()

If your publisher depends on a connection that may fail during startup, initialize reporter first without publishing, create the dependency, then attach the publisher with SetPublisher. This lets reporter print bootstrap connection errors before external publishing is available.

reporter.Init(reporter.Config{
    AppName:          "payment-service",
    AppEnv:           "production",
    EnablePublishing: false,
})
defer reporter.Close()

redisClient := redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
})

if err := redisClient.Ping(ctx).Err(); err != nil {
    return reporter.WrapWithSeverity(err, reporter.SeverityCritical, "Failed to connect to Redis")
}

reporter.SetPublisher(reporter.NewRedisListPublisher(redisClient, "service-alerts"))
Graceful Shutdown & Fatal Errors (reporter.Flush)

Because the reporter publishes logs asynchronously in a background goroutine to maintain high performance, forcing an immediate application exit (like log.Fatal or os.Exit) might terminate the program before the background logs can reach Redis or Kafka.

To prevent log data loss during a critical startup failure or a standard graceful shutdown sequence, call reporter.Flush(). This function blocks the application execution until all pending background publishing operations have safely finished.

func main() {
    reporter.Init(reporter.Config{
        AppName:          "payment-service",
        AppEnv:           "production",
        EnablePublishing: true,
    })
    defer reporter.Close()

    // Example: Handling a fatal database startup failure
    if err := connectDatabase(); err != nil {
        wrappedErr := reporter.AutoWrap(err)
        
        reporter.Flush() // <-- CRITICAL: Wait for the background log to be sent safely
        log.Fatalf("System failed to boot: %v", wrappedErr)
    }
}

`Config` fields:

| Field                      | Required | Description                                                                                                                         |
| -------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `AppName`                  | No       | Service name included in every report. Defaults to `unknown-service`.                                                               |
| `AppEnv`                   | No       | Runtime environment. Defaults to `development`. `production` makes `Error()` return JSON.                                           |
| `KafkaBrokers`             | Kafka    | Kafka broker list, for example `[]string{"kafka-1:9092", "kafka-2:9092"}`.                                                          |
| `KafkaTopic`               | Kafka    | Kafka topic used for alert messages.                                                                                                |
| `EnablePublishing`         | No       | Enables Kafka publishing when `KafkaBrokers` and `KafkaTopic` are also provided. Defaults to `false`.                               |
| `Publisher`                | No       | Optional publisher, for example `NewRedisListPublisher(...)` or a custom publisher. When provided with `EnablePublishing=true`, it is used instead of Kafka config. |
| `PublishMinSeverity`       | No       | Minimum severity that may be published. Defaults to `danger`, so handled errors such as duplicate data are not sent to Kafka/Redis. |
| `AutoWrapFallbackSeverity` | No       | Severity for `AutoWrap` errors that do not match any known pattern. Defaults to `danger`.                                           |

Publishing is non-blocking. When `EnablePublishing=true` and either `Publisher` or Kafka configuration is complete, the package sends the structured payload in a background goroutine. If publishing fails, the failure is written to `stderr` so the original error is not lost.

Severity values:

| Severity   | Typical Use                                                         | Published by Default |
| ---------- | ------------------------------------------------------------------- | -------------------- |
| `info`     | Handled business/data cases such as duplicate data or not found.    | No                   |
| `warning`  | Recoverable issues that should be watched but do not need alerts.   | No                   |
| `danger`   | Serious application issues, HTTP 500-style failures, logic anomaly. | Yes                  |
| `critical` | Infrastructure outage such as database/API connection failure.      | Yes                  |

Set `PublishMinSeverity` when you want a different alert threshold:

```go
reporter.Init(reporter.Config{
    AppName:            "payment-service",
    AppEnv:             "production",
    EnablePublishing:   true,
    KafkaBrokers:       []string{"kafka-1:9092"},
    KafkaTopic:         "service-alerts",
    PublishMinSeverity: reporter.SeverityCritical,
})

Set AutoWrapFallbackSeverity when unknown AutoWrap errors should not automatically trigger Telegram alerts:

reporter.Init(reporter.Config{
    AppName:                  "payment-service",
    AppEnv:                   "production",
    EnablePublishing:         true,
    KafkaBrokers:             []string{"kafka-1:9092"},
    KafkaTopic:               "service-alerts",
    PublishMinSeverity:       reporter.SeverityDanger,
    AutoWrapFallbackSeverity: reporter.SeverityWarning,
})

If your application stores config in environment variables, read and map them in your own service before calling Init:

reporter.Init(reporter.Config{
    AppName:          os.Getenv("APP_NAME"),
    AppEnv:           os.Getenv("APP_ENV"),
    KafkaBrokers:     strings.Split(os.Getenv("KAFKA_BROKERS"), ","),
    KafkaTopic:       os.Getenv("KAFKA_TOPIC"),
    EnablePublishing: os.Getenv("APP_ENV") == "production",
})

Installation

go get github.com/learncodexx/reporter/v2

If this package is used from a private/local module, replace the module path with your repository import path.

Basic Usage

package main

import (
    "errors"

    "github.com/learncodexx/reporter/v2"
)

func main() {
    reporter.Init(reporter.Config{
        AppName: "example-service",
        AppEnv:  "development",
    })
    defer reporter.Close()

    err := doWork()
    if err != nil {
        reporter.AutoWrap(err)
        return
    }
}

func doWork() error {
    return errors.New("connection refused")
}

AutoWrap inspects the raw error text and assigns a useful error_type and description when it recognizes common patterns.

Use AutoWrap as a convenient fallback when the application only has an ordinary error. When your application already knows stronger context, prefer the explicit APIs:

  • Wrap when you know the business description.
  • WrapWithSeverity when you know the alert priority.
  • WrapHTTPStatus when the HTTP handler already knows the response status code.
  • WrapReport when you want to provide several signals in one call.

Operational Logging (reporter.Info)

Use reporter.Info to print successful actions, initialization milestones, or routine telemetry. This function is designed strictly for tracking healthy system behavior and only writes to standard output (stdout).

It never triggers Kafka or external alerting pipelines, making it completely safe from polluting your alert notification channels (such as Telegram or Slack).

Usage Example
package main

import "github.com/learncodexx/reporter/v2"

func StartServer() {
    // Log successful milestones without bothering alerting consumers
    reporter.Info("SERVER", "HTTP server smoothly binding to port %d", 8080)
    reporter.Info("DATABASE", "Successfully verified connection handshake with PostgreSQL cluster")
}

Custom Description

Use Wrap when the application already knows the business context and you want to provide a specific description.

err := repository.SaveOrder(order)
if err != nil {
    return reporter.Wrap(err, "Failed to save checkout order after payment was confirmed")
}

This keeps the original error in raw_error while adding a human-readable explanation in description.

HTTP Status Classification

Use WrapHTTPStatus when the handler already knows the final response status. This is more reliable than asking AutoWrap to infer HTTP 500 from an error string.

if err := checkout(order); err != nil {
    return reporter.WrapHTTPStatus(err, 500, "Checkout handler failed")
}

When you know more than one signal, use WrapReport:

if err := checkout(order); err != nil {
    return reporter.WrapReport(err, reporter.ReportOptions{
        Description: "Checkout handler failed",
        StatusCode:  500,
        Severity:    reporter.SeverityDanger,
    })
}

HTTP status mapping:

Status Code Error Type Severity
>=500 INTERNAL_SERVER_ERROR critical
429 RATE_LIMIT_ERROR warning
401 AUTHENTICATION_ERROR warning
403 AUTHORIZATION_ERROR warning
404 DATA_NOT_FOUND info
400-499 VALIDATION_ERROR info

Automatic Error Classification

AutoWrap currently recognizes these common error families:

Error Type Matched Text Examples Description Purpose
INFRASTRUCTURE_ERROR connection refused, dial tcp, no route to host, broker not available Network, database, broker, or third-party connectivity failures.
DATABASE_CONSTRAINT duplicate key, violates unique constraint, foreign key constraint, not null constraint Database constraint conflicts while saving data.
DATABASE_QUERY_ERROR deadlock detected, relation does not exist, unknown column Query, schema, lock, or transaction failures.
TIMEOUT_ERROR context deadline exceeded, gateway timeout, i/o timeout Work stopped because the execution deadline was reached.
DATA_NOT_FOUND no rows in result set, record not found, 404 Requested data does not exist.
VALIDATION_ERROR validation failed, invalid input, missing required, 400, 422 Request/input is invalid and usually handled by the application.
AUTHENTICATION_ERROR unauthorized, invalid token, jwt expired, 401 Authentication is missing, invalid, or expired.
AUTHORIZATION_ERROR forbidden, permission denied, access denied, 403 Caller does not have permission.
RATE_LIMIT_ERROR rate limit, too many requests, quota exceeded, 429 Rate limit or quota was exceeded.
SERIALIZATION_ERROR json:, cannot unmarshal, invalid character, yaml: Encoding or decoding structured data failed.
EXTERNAL_SERVICE_ERROR service unavailable, bad gateway, upstream, 502, 503 Downstream or third-party service failed.
RESOURCE_EXHAUSTION out of memory, no space left on device, too many open files Service is running out of critical system resources.
CONFIGURATION_ERROR missing environment variable, invalid configuration, missing config Runtime configuration is missing or invalid.
LOGIC_ANOMALY panic, nil pointer, index out of range, invalid state, invariant Unexpected application logic failure.
INTERNAL_SERVER_ERROR status 500, http 500, internal server error Service returned an HTTP 500-style failure.
GENERAL_ERROR Anything else Fallback for errors that do not match known patterns.

Automatic severity mapping:

Error Type Severity
DATABASE_CONSTRAINT info or warning, depending on the constraint
DATA_NOT_FOUND info
VALIDATION_ERROR info
AUTHENTICATION_ERROR warning
AUTHORIZATION_ERROR warning
RATE_LIMIT_ERROR warning
TIMEOUT_ERROR danger
DATABASE_QUERY_ERROR danger
SERIALIZATION_ERROR danger
EXTERNAL_SERVICE_ERROR danger
LOGIC_ANOMALY danger
INTERNAL_SERVER_ERROR danger
RESOURCE_EXHAUSTION critical
CONFIGURATION_ERROR critical
GENERAL_ERROR AutoWrapFallbackSeverity, default danger

If AutoWrap does not match any known pattern, it returns GENERAL_ERROR. The severity comes from AutoWrapFallbackSeverity; when that config is empty, reporter uses danger. This keeps unknown 500-style failures visible by default, while still allowing a service to lower the fallback to warning if it has many known-but-unclassified handled errors.

Production Kafka Example

package main

import (
    "github.com/learncodexx/reporter/v2"
)

func main() {
    reporter.Init(reporter.Config{
        AppName:          "payment-service",
        AppEnv:           "production",
        KafkaBrokers:     []string{"kafka-1:9092", "kafka-2:9092"},
        KafkaTopic:       "service-alerts",
        EnablePublishing: true,
    })
    defer reporter.Close()

    if err := run(); err != nil {
        reporter.AutoWrap(err)
        return
    }
}

The Kafka message value is the JSON CustomError payload. The message key is the service name, which helps consumers group alerts by service. A Telegram alert worker can consume KAFKA_TOPIC, decode the JSON, and format a Telegram message using service, environment, file, line, error_type, description, and raw_error.

Production Redis List Example

Use NewRedisListPublisher when you want reporter to append structured error reports to a Redis list. The Redis publisher serializes CustomError to JSON and stores it with the Redis RPUSH command.

package main

import (
    "github.com/learncodexx/reporter/v2"
    "github.com/redis/go-redis/v9"
)

func main() {
    redisClient := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })
    defer redisClient.Close()

    reporter.Init(reporter.Config{
        AppName:          "payment-service",
        AppEnv:           "production",
        EnablePublishing: true,
        Publisher:        reporter.NewRedisListPublisher(redisClient, "service-alerts"),
    })
    defer reporter.Close()

    if err := run(); err != nil {
        reporter.AutoWrap(err)
        return
    }
}

Redis list consumers receive the same JSON CustomError payload used by Kafka publishing. A Telegram alert worker can call BLPOP service-alerts 0 or LPOP service-alerts, decode the JSON value, and format a notification from fields such as service, environment, severity, error_type, description, and raw_error.

Custom Publisher

Use a custom publisher when you want a file spool, webhook, stream, queue, or another transport.

type Publisher interface {
    Publish(ctx context.Context, report *reporter.CustomError) error
}

Example webhook-style publisher:

type WebhookPublisher struct {
    endpoint string
    client   *http.Client
}

func (p *WebhookPublisher) Publish(ctx context.Context, report *reporter.CustomError) error {
    payload, err := json.Marshal(report)
    if err != nil {
        return err
    }

    req, err := http.NewRequestWithContext(ctx, http.MethodPost, p.endpoint, bytes.NewReader(payload))
    if err != nil {
        return err
    }
    req.Header.Set("Content-Type", "application/json")

    resp, err := p.client.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    if resp.StatusCode >= 400 {
        return fmt.Errorf("webhook returned status %d", resp.StatusCode)
    }

    return nil
}

Then pass it to Init:

reporter.Init(reporter.Config{
    AppName:          "payment-service",
    AppEnv:           "production",
    EnablePublishing: true,
    Publisher: &WebhookPublisher{
        endpoint: "https://alerts.example.com/reporter",
        client:   http.DefaultClient,
    },
})

Telegram Alert Message Example

A Kafka consumer or Redis list worker can convert the JSON payload into a message like this:

[production] payment-service
[critical] INFRASTRUCTURE_ERROR
Failed to connect to a database or third-party API (timeout/refused)

Location: service/order.go:42
Function: service.CreateOrder
Raw error: dial tcp database:5432 connection refused
Time: 2026-06-04 14:35:12

For custom logic anomalies, use explicit severity:

if err := validateState(order); err != nil {
    return reporter.WrapWithSeverity(
        err,
        reporter.SeverityDanger,
        "Checkout state is inconsistent after payment confirmation",
    )
}

API Summary

type Config struct {
    AppName          string
    AppEnv           string
    KafkaBrokers     []string
    KafkaTopic       string
    EnablePublishing bool
    Publisher        Publisher
    PublishMinSeverity string
    AutoWrapFallbackSeverity string
}

type Publisher interface {
    Publish(ctx context.Context, report *CustomError) error
}

type ClosePublisher interface {
    Close() error
}

type ReportOptions struct {
    Description string
    Severity    string
    ErrorType   string
    StatusCode  int
}

func NewKafkaPublisher(brokers []string, topic string) *KafkaPublisher
func NewRedisPublisher(client *redis.Client, listName string) *RedisPublisher
func NewRedisListPublisher(client *redis.Client, listName string) *RedisPublisher
func Init(cfg Config)
func SetPublisher(p Publisher)
func Close()
func Flush()
func AutoWrap(err error) error
func Wrap(err error, customDesc string) error
func WrapWithSeverity(err error, severity, customDesc string) error
func WrapHTTPStatus(err error, statusCode int, customDesc string) error
func WrapReport(err error, opts ReportOptions) error
  • Init(cfg) stores reporter configuration and prepares publishing when EnablePublishing is true and either Publisher or Kafka settings are complete.
  • SetPublisher(p) attaches or replaces the active publisher after Init; passing nil disables publishing.
  • Close() closes the active publisher during graceful shutdown when it implements Close() error.
  • Flush() blocks until all pending background publishing goroutines are complete, guaranteeing zero data loss before forcing an exit.
  • AutoWrap(err) returns nil for nil input, otherwise prints and returns a structured CustomError with automatic classification.
  • Wrap(err, customDesc) returns nil for nil input, otherwise prints and returns a structured CustomError using your custom description.
  • WrapWithSeverity(err, severity, customDesc) works like Wrap but lets application code decide alert priority.
  • WrapHTTPStatus(err, statusCode, customDesc) uses the HTTP status code as the primary classification signal.
  • WrapReport(err, opts) accepts description, severity, error type, and status code in one call.

The returned error can be type-asserted to *reporter.CustomError when you need direct access to fields such as ErrorType, File, Line, or FunctionName:

err := reporter.AutoWrap(rawErr)
if customErr, ok := err.(*reporter.CustomError); ok {
    _ = customErr.ErrorType
    _ = customErr.File
    _ = customErr.Line
}

Internal Helpers

The package also has several unexported helper functions. They are implementation details and are not part of the public API:

Function Purpose
newError Builds CustomError, captures caller metadata, prints it, and triggers publishing when enabled.
publish Sends CustomError to the configured publisher.
containsAny Checks whether a string contains at least one expected substring.
byteContains Performs byte-level substring matching.
jsonErrTextLower Converts ASCII uppercase letters to lowercase.

These helpers are not exported, so application code should use only Init, Close, AutoWrap, Wrap, Config, and CustomError.

Notes

  • Always call Init(reporter.Config{...}) before wrapping errors if you want service, environment, and publishing to be configured correctly.
  • Always call Close() during shutdown in services that publish externally.
  • Do not use this package as a replacement for normal application error handling. It is intended for reporting and alerting.

Documentation

Overview

Package reporter turns ordinary Go errors into structured reports that are suitable for local logs, production JSON logs, and external alerting.

A report includes the caller file path, line number, function name, service, environment, timestamp, raw error, error type, and human-readable description. Reports can be published to Kafka or a custom publisher so a separate worker can forward the alert to Telegram or another notification channel.

Initialize the package once during application startup:

reporter.Init(reporter.Config{
	AppName: "payment-service",
	AppEnv:  "development",
})
defer reporter.Close()

Use AutoWrap when reporter should classify the error from its text:

if err := run(); err != nil {
	return reporter.AutoWrap(err)
}

Use Wrap when the application can provide better business context:

if err := repository.SaveOrder(order); err != nil {
	return reporter.Wrap(err, "Failed to save checkout order after payment was confirmed")
}

Index

Constants

View Source
const (
	SeverityInfo     = "info"
	SeverityWarning  = "warning"
	SeverityDanger   = "danger"
	SeverityCritical = "critical"
)

Severity values describe how urgent a report is.

Variables

This section is empty.

Functions

func AutoWrap

func AutoWrap(err error) error

AutoWrap converts an ordinary error into a structured report with automatic classification.

AutoWrap returns nil when err is nil. Otherwise it inspects err.Error() and assigns an error type and description for known patterns such as connection failures, duplicate keys, deadline timeouts, and missing data. The returned error captures the caller file path, line number, and function name. In production, the report is also published when Init configured a publisher.

Example:

if err := repository.FindUser(id); err != nil {
	return reporter.AutoWrap(err)
}

func Close

func Close()

Close releases the Kafka writer used by reporter.

Call Close during graceful shutdown after Init has been called. It is safe to call even when Kafka publishing is not enabled.

Example:

defer reporter.Close()

func Flush added in v2.0.4

func Flush()

Flush blocks the calling goroutine until all pending background publishing operations have safely finished executing.

This function should be called during a graceful shutdown sequence or immediately before forcing an application exit (e.g., inside log.Fatalf or after a critical startup failure) to guarantee zero log data loss.

Example:

func main() {
    rdb, err := ConnectRedis()
    if err != nil {
        reporter.AutoWrap(err)
        reporter.Flush() // Ensures the error above is sent to Redis before exiting
        log.Fatalf("Fatal startup error: %v", err)
    }
}

func Info

func Info(tag string, format string, args ...any)

Info logs a general informational message or a success indicator.

Unlike AutoWrap or Wrap, Info is designed strictly for operational tracking (e.g., "Database connected successfully", "Kafka consumer started"). It only outputs to standard synchronization streams (stdout) and will NEVER publish payloads to Kafka or external alert destinations, preventing log pollution.

In non-production environments, it formats the output with terminal-friendly colors synchronized with the CustomError aesthetic. In production, it outputs a structured, single-line JSON log ideal for indexing tools like Elasticsearch.

Example:

func ConnectDB() {
    db, err := sql.Open("postgres", dsn)
    if err != nil {
        reporter.AutoWrap(err) // Sent to Kafka as CRITICAL
        return
    }

    // Log success locally/json without triggering alerting pipelines
    reporter.Info("DATABASE", "Successfully connected to PostgreSQL at %s:%d", "127.0.0.1", 5432)
}

func Init

func Init(cfg Config)

Init applies reporter configuration for the current service.

Call Init once during application startup before using AutoWrap or Wrap. It stores the service name, environment, and optional publishing settings. When EnablePublishing is true and a publisher or complete Kafka settings are provided, every reported error can be published asynchronously.

Example:

reporter.Init(reporter.Config{
	AppName: "payment-service",
	AppEnv:  "development",
})
defer reporter.Close()

func SetPublisher added in v2.0.2

func SetPublisher(p Publisher)

SetPublisher enables external publishing after Init has already configured service metadata. This is useful when the publisher depends on a connection that must be created after reporter is available for bootstrap errors.

func Wrap

func Wrap(err error, customDesc string) error

Wrap converts an ordinary error into a structured report with a custom description.

Wrap returns nil when err is nil. Use Wrap when the application can provide better business context than automatic classification. The original error is preserved in RawError, while customDesc is stored in Description. The returned error captures the caller file path, line number, and function name. In production, the report is also published when Init configured a publisher.

Example:

if err := repository.SaveOrder(order); err != nil {
	return reporter.Wrap(err, "Failed to save checkout order after payment was confirmed")
}

func WrapHTTPStatus

func WrapHTTPStatus(err error, statusCode int, customDesc string) error

WrapHTTPStatus converts an ordinary error into a structured report using the HTTP status code as the primary classification signal.

func WrapReport

func WrapReport(err error, opts ReportOptions) error

WrapReport converts an ordinary error into a structured report using explicit options supplied by the application.

func WrapWithSeverity

func WrapWithSeverity(err error, severity, customDesc string) error

WrapWithSeverity converts an ordinary error into a structured report with a custom description and explicit severity.

Types

type ClosePublisher

type ClosePublisher interface {
	Close() error
}

ClosePublisher can be implemented by publishers that hold resources.

type Config

type Config struct {
	AppName                  string
	AppEnv                   string
	KafkaBrokers             []string
	KafkaTopic               string
	EnablePublishing         bool
	Publisher                Publisher
	PublishMinSeverity       string
	AutoWrapFallbackSeverity string
}

Config holds all the configuration parameters required to initialize the reporter. Passing this struct explicitly via function parameters provides better flexibility and decouples the package from direct environment variable access.

type CustomError

type CustomError struct {
	Timestamp    string `json:"timestamp"`
	Environment  string `json:"environment"`
	Service      string `json:"service"`
	Severity     string `json:"severity"`
	ErrorType    string `json:"error_type"`
	Description  string `json:"description"`
	RawError     string `json:"raw_error"`
	StatusCode   int    `json:"status_code,omitempty"`
	File         string `json:"file"`
	Line         int    `json:"line"`
	FunctionName string `json:"function"`
}

CustomError is the structured error payload produced by this package.

It contains the information needed for logs and alerts: timestamp, environment, service name, error type, human-readable description, raw error text, caller file path, caller line number, and caller function name. This structure is passed to publishers and can be serialized to JSON for downstream alert delivery, such as Telegram notifications.

func (*CustomError) Error

func (e *CustomError) Error() string

Error returns a formatted representation of the structured error.

In non-production environments it returns a colored terminal-friendly string containing the timestamp, file, line, error type, description, and raw error. In production it returns the JSON representation of CustomError, which is suitable for logs, Kafka messages, and alert consumers.

type KafkaPublisher

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

KafkaPublisher publishes error reports to Kafka as JSON.

func NewKafkaPublisher

func NewKafkaPublisher(brokers []string, topic string) *KafkaPublisher

NewKafkaPublisher creates a Kafka-backed reporter publisher.

func (*KafkaPublisher) Close

func (p *KafkaPublisher) Close() error

Close releases the Kafka writer.

func (*KafkaPublisher) Publish

func (p *KafkaPublisher) Publish(ctx context.Context, report *CustomError) error

Publish serializes the report to JSON and writes it to Kafka.

type Publisher

type Publisher interface {
	Publish(ctx context.Context, report *CustomError) error
}

Publisher sends a structured error report to an external destination.

Implement this interface when you want to publish reports to something other than the built-in Kafka publisher, such as Redis, a file spool, or a webhook.

type RedisPublisher added in v2.0.1

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

RedisPublisher implements the reporter.Publisher interface by appending structured error reports to a Redis list.

Reports are stored with RPUSH, so consumers can process them in FIFO order using LPOP or BLPOP from the same list.

func NewRedisListPublisher added in v2.0.3

func NewRedisListPublisher(client *redis.Client, listName string) *RedisPublisher

NewRedisListPublisher creates a Redis-backed publisher that appends reports to a Redis list.

It is equivalent to NewRedisPublisher and exists as the clearer constructor for new code.

func NewRedisPublisher added in v2.0.1

func NewRedisPublisher(client *redis.Client, listName string) *RedisPublisher

NewRedisPublisher creates and initializes a new Redis-backed reporter publisher. It keeps the historical constructor name for compatibility; the destination is now a Redis list, not channel broadcasting.

Parameters:

  • client: An active *redis.Client connection instance.
  • listName: The target Redis list name where reports will be appended.

Example:

pub := reporter.NewRedisPublisher(rdbClient, "app_error_logs")

func (*RedisPublisher) Publish added in v2.0.1

func (p *RedisPublisher) Publish(ctx context.Context, report *CustomError) error

Publish serializes the structured CustomError report into a JSON payload and appends it to the configured Redis list using the RPUSH command.

It satisfies the reporter.Publisher interface requirements. Returns an error if JSON marshalling fails or if the Redis server is unreachable.

type ReportOptions

type ReportOptions struct {
	Description string
	Severity    string
	ErrorType   string
	StatusCode  int
}

ReportOptions describes explicit context for a reported error.

Jump to

Keyboard shortcuts

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