How to Enable Debug Logging in Telego: Complete Configuration Guide

Enable full debug logging in Telego by setting both Bot.debugMode (via WithDebugMode()) and logger.DebugMode (via WithDefaultDebugLogger() or a custom logger), then inspect raw API requests and responses in your console.

Telego is a fast, feature-complete Telegram Bot API library for Go. When building bots with mymmrac/telego, enabling debug logging helps you inspect raw HTTP requests, JSON payloads, and API responses during development. This guide explains the dual-flag system that controls debug output and provides production-ready configuration examples.

Understanding Telego's Dual Debug System

Telego implements debug logging through two independent flags that must both be enabled for complete visibility:

Flag Purpose Location
logger.DebugMode Controls whether Debugf calls actually write output. When false, debug messages are discarded at the logger level. logger.go lines 84-88
Bot.debugMode Controls whether the bot includes full request payload data in debug output (the "API call to ... with data: ..." line). bot.go lines 43-49

Critical: If you only set Bot.debugMode without configuring the logger's DebugMode, the bot prepares payload strings but the logger discards them. Conversely, enabling the logger's DebugMode without Bot.debugMode shows response data but hides request payloads.

Enabling Debug Logging via Bot Options

Telego provides BotOption functions in bot_options.go to configure both flags. Choose the approach that matches your verbosity requirements:

  • WithDebugMode() — Sets Bot.debugMode = true. Required for request payload logging. (Source: bot_options.go lines 102-107)

  • WithDefaultDebugLogger() — Replaces the default logger with DebugMode: true and PrintErrors: true. Best for development. (Source: bot_options.go lines 81-85)

  • WithDefaultLogger(debugMode, printErrors) — Fine-grained control over the built-in logger. Pass true for debugMode to enable Debugf output. (Source: bot_options.go lines 50-61)

  • WithExtendedDefaultLogger(debugMode, printErrors, replacer) — Same as above but accepts a strings.Replacer for token redaction in logs. (Source: bot_options.go lines 64-78)

  • WithLogger(customLogger) — Inject any struct implementing the Logger interface. You must set its DebugMode field to true. (Source: bot_options.go lines 92-99)

  • WithDiscardLogger() — Disables all logging (production use). Equivalent to WithDefaultLogger(false, false). (Source: bot_options.go lines 87-90)

Practical Implementation Examples

Quick Start: One-Liner Setup

Enable full debug output using the convenience option that configures both the bot and logger:

package main

import (
    "github.com/mymmrac/telego"
)

func main() {
    bot, err := telego.NewBot("YOUR_BOT_TOKEN",
        telego.WithDefaultDebugLogger(), // Enables logger.DebugMode and PrintErrors
        telego.WithDebugMode(),           // Enables Bot.debugMode for request payloads
    )
    if err != nil {
        panic(err)
    }
    
    // Both flags are now active; all API calls will show full request/response data
    _ = bot
}

Output: Every API call prints the full URL, JSON payload, and raw response body.

Separate Control: Request Payloads Only

If you want request payload logging but prefer to handle errors separately:

bot, err := telego.NewBot("TOKEN",
    telego.WithDebugMode(),               // Enable request payload logging
    telego.WithDefaultLogger(true, false), // Enable debug output, suppress errors
)

Result: You see "API call to ... with data: ..." lines, but error messages are suppressed.

Custom Logger Implementation

For advanced use cases (e.g., structured logging with slog or zap):

type structuredLogger struct {
    debugMode bool
}

func (l *structuredLogger) Debugf(format string, args ...any) {
    if l.debugMode {
        slog.Debug(fmt.Sprintf(format, args...))
    }
}

func (l *structuredLogger) Errorf(format string, args ...any) {
    slog.Error(fmt.Sprintf(format, args...))
}

func main() {
    customLog := &structuredLogger{debugMode: true}
    
    bot, err := telego.NewBot("TOKEN",
        telego.WithLogger(customLog),
        telego.WithDebugMode(),
    )
    // ...
}

Note: Your custom logger must check its own debugMode flag inside Debugf, matching the behavior in logger.go.

Disabling Logging in Production

To completely silence the bot (default logger starts with DebugMode: false as defined in logger.go lines 45-53):

bot, err := telego.NewBot("TOKEN",
    telego.WithDiscardLogger(), // Equivalent to WithDefaultLogger(false, false)
)

Key Source Files and Implementation Details

Understanding the source helps debug configuration issues:

  • logger.go — Contains the default logger implementation. The Debugf method checks l.DebugMode before writing (lines 84-88). The newDefaultLogger constructor initializes DebugMode: false (lines 45-53).

  • bot.go — The performRequest method checks b.debugMode before logging request payloads (lines 43-49). If debugMode is true, it logs the API endpoint and JSON data.

  • bot_options.go — Defines all configuration helpers. Options like WithDefaultDebugLogger wrap the logger initialization, while WithDebugMode toggles the bot's payload logging flag.

Summary

  • Two flags control debug output: logger.DebugMode (controls whether debug messages are written) and Bot.debugMode (controls whether request payloads are included in logs).
  • Use WithDefaultDebugLogger() to enable the built-in logger's debug output and error printing in one option.
  • Always pair WithDebugMode() with a logger configured for debug output to see full request/response traces.
  • For production, use WithDiscardLogger() or WithDefaultLogger(false, false) to silence all output.
  • Custom loggers must implement the Logger interface and respect their own DebugMode flag inside Debugf.

Frequently Asked Questions

Why don't I see debug output after using WithDebugMode()?

You are likely missing the logger configuration. WithDebugMode() only sets Bot.debugMode, which controls whether the bot includes request payload strings in its debug calls. However, the default logger initializes with DebugMode: false (as seen in logger.go lines 45-53), causing it to discard all debug messages. You must also use WithDefaultDebugLogger() or WithDefaultLogger(true, ...) to enable the actual output.

What is the difference between WithDefaultDebugLogger() and WithDefaultLogger(true, true)?

Both enable debug output, but WithDefaultDebugLogger() is a convenience wrapper that explicitly sets both DebugMode and PrintErrors to true (source: bot_options.go lines 81-85). WithDefaultLogger(true, true) achieves the same result but requires you to pass the boolean arguments explicitly. Use WithDefaultDebugLogger() for brevity during development, and WithDefaultLogger() when you need fine-grained control over error printing.

How can I redact sensitive tokens from debug logs?

Use WithExtendedDefaultLogger(debugMode, printErrors, replacer) and provide a strings.Replacer that substitutes your token with a placeholder. For example:

replacer := strings.NewReplacer("YOUR_BOT_TOKEN", "[REDACTED]")
bot, err := telego.NewBot("YOUR_BOT_TOKEN",
    telego.WithExtendedDefaultLogger(true, true, replacer),
    telego.WithDebugMode(),
)

This replaces the sensitive string wherever it appears in the log output, including request payloads and URLs.

Can I use a structured logger like Zap or Slog with Telego?

Yes. Implement the Logger interface from logger.go which requires two methods: Debugf(format string, args ...any) and Errorf(format string, args ...any). In your implementation, call your structured logger's methods (e.g., slog.Debug() or logger.Info()). Ensure your wrapper checks an internal debugMode flag inside Debugf to match Telego's expected behavior, or always delegate to the underlying logger if you want unconditional debug output.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →