# How to Enable Debug Logging in Telego: Complete Configuration Guide

> Learn how to enable debug logging in Telego with this complete configuration guide. Inspect raw API requests and responses in your console for effective troubleshooting. Get started now!

- Repository: [Artem Yadelskyi/telego](https://github.com/mymmrac/telego)
- Tags: how-to-guide
- Published: 2026-03-07

---

**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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/bot_options.go) lines 102-107)

- **`WithDefaultDebugLogger()`** — Replaces the default logger with `DebugMode: true` and `PrintErrors: true`. Best for development. (Source: [`bot_options.go`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/bot_options.go) lines 92-99)

- **`WithDiscardLogger()`** — Disables all logging (production use). Equivalent to `WithDefaultLogger(false, false)`. (Source: [`bot_options.go`](https://github.com/mymmrac/telego/blob/main/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:

```go
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:

```go
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`):

```go
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`](https://github.com/mymmrac/telego/blob/main/logger.go).

### Disabling Logging in Production

To completely silence the bot (default logger starts with `DebugMode: false` as defined in [`logger.go`](https://github.com/mymmrac/telego/blob/main/logger.go) lines 45-53):

```go
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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/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`](https://github.com/mymmrac/telego/blob/main/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:

```go
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`](https://github.com/mymmrac/telego/blob/main/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.