Skip to main content

Logging and Debugging

Graz includes a comprehensive logging system to help you debug wallet connections, transactions, and multi-chain operations during development and monitor errors in production.

info

Logging is disabled by default and must be explicitly enabled through configuration.

Quick Start

Enable Logging via GrazProvider

The easiest way to enable logging is through the GrazProvider:

import { QueryClientProvider } from "@tanstack/react-query";
import { GrazProvider, LogLevel, LogCategory } from "graz";

const queryClient = new QueryClient();

export default function App() {
return (
<QueryClientProvider client={queryClient}>
<GrazProvider
grazOptions={{
chains: [cosmoshubChainInfo, osmosisChainInfo],
logger: {
enabled: true, // Must explicitly enable
level: LogLevel.DEBUG,
categories: [LogCategory.WALLET, LogCategory.TRANSACTION],
},
}}
>
<YourApp />
</GrazProvider>
</QueryClientProvider>
);
}

Enable Logging via configureGraz

You can also configure logging directly:

import { configureGraz, LogLevel, LogCategory } from "graz";

configureGraz({
chains: [cosmoshubChainInfo, osmosisChainInfo],
logger: {
enabled: true, // Must explicitly enable
level: LogLevel.INFO,
categories: [LogCategory.WALLET],
},
});

This is useful when:

  • You're not using React
  • You need to configure Graz before rendering
  • You want to dynamically change logger settings

Default Behavior

ConfigurationLogger State
No logger config❌ Disabled (default)
logger: { enabled: true }✅ Enabled
logger: { enabled: false }❌ Disabled
window.__GRAZ_DEBUG__ = true✅ Force enabled

Log Levels

Graz supports five log levels that control verbosity:

import { LogLevel } from "graz";

enum LogLevel {
ERROR = 0, // Only errors
WARN = 1, // Errors and warnings
INFO = 2, // Errors, warnings, and info
DEBUG = 3, // All logs including debug
TRACE = 4, // Most verbose (not currently used)
}

Single Level

Set a minimum level - all messages at this level and above will be logged:

// Production: Only errors
logger: { enabled: true, level: LogLevel.ERROR }

// Development: All logs
logger: { enabled: true, level: LogLevel.DEBUG }

// Moderate logging
logger: { enabled: true, level: LogLevel.INFO }

Multiple Levels

Log only specific levels by passing an array:

// Only errors and warnings
logger: {
enabled: true,
level: [LogLevel.ERROR, LogLevel.WARN]
}

All Levels

Log everything by setting level to undefined:

// Log all levels
logger: {
enabled: true,
level: undefined
}

Log Categories

Filter logs by specific categories to focus on what you need:

import { LogCategory } from "graz";

enum LogCategory {
WALLET = "wallet", // Wallet connections, disconnections
TRANSACTION = "transaction", // Token transfers, contract execution
QUERY = "query", // Blockchain queries, client creation
STORE = "store", // State management, chain config
MULTICHAIN = "multichain", // Multi-chain operations
EVENT = "event", // Wallet events (ping, keystore changes)
PERFORMANCE = "performance", // Performance timing
}

Category Examples

// Only wallet operations
logger: {
enabled: true,
categories: [LogCategory.WALLET]
}

// Transaction and query logs
logger: {
enabled: true,
categories: [LogCategory.TRANSACTION, LogCategory.QUERY]
}

// Everything (default)
logger: {
enabled: true,
categories: undefined // undefined = all categories
}

What Gets Logged?

Wallet Operations

[graz] INFO [wallet] [connect] Connection successful
{ walletType: "keplr", chainCount: 2, chainIds: ["cosmoshub-4", "osmosis-1"] }

Transactions

[graz] INFO [transaction] [sendTokens] Transaction broadcasted
{ txHash: "ABC123...", senderAddress: "cosmos1...", amount: "1000000" }

Multi-chain Operations

[graz] DEBUG [multichain] [useStargateClient] Starting parallel operations
{ chainCount: 3, concurrency: 3, chainIds: ["cosmoshub-4", "osmosis-1", "juno-1"] }

Errors

[graz] ERROR [wallet] [connect] Connection failed
{ error: "User rejected request", walletType: "keplr", chainId: "cosmoshub-4" }

Dynamic Configuration

Change logger settings at runtime:

import { getLogger, LogLevel, LogCategory } from "graz";

const logger = getLogger();

// Enable/disable
logger.enable();
logger.disable();

// Change log level
logger.setLevel(LogLevel.DEBUG);
logger.setLevel([LogLevel.ERROR, LogLevel.WARN]);
logger.setLevel(undefined); // All levels

// Change categories
logger.setCategories([LogCategory.WALLET, LogCategory.TRANSACTION]);
logger.setCategories(undefined); // All categories

Performance Timing

Some operations include automatic performance timing:

// Automatically timed operations:
// - connect() - Wallet connection time
// - Multi-chain operations - Parallel execution time
// - Contract queries - Query execution time

Performance logs appear as:

[graz] DEBUG [performance] ⏱️ connect: 1234.56ms

Error Tracking Integration

Integrate with error tracking services like Sentry:

import * as Sentry from "@sentry/react";
import { configureLogger, LogLevel } from "graz";

configureLogger({
enabled: true,
level: LogLevel.ERROR,
errorReporter: {
captureException: (error, context) => {
Sentry.captureException(error, { extra: context });
},
},
});

This automatically sends all ERROR-level logs to your error tracking service with full context.

Development

<GrazProvider
grazOptions={{
chains: [...],
logger: {
enabled: true,
level: LogLevel.DEBUG,
categories: undefined, // All categories
}
}}
>

Production

<GrazProvider
grazOptions={{
chains: [...],
logger: {
enabled: true,
level: LogLevel.ERROR,
errorReporter: sentryReporter,
}
}}
>

Environment-based

const isDevelopment = process.env.NODE_ENV === "development";

<GrazProvider
grazOptions={{
chains: [...],
logger: isDevelopment
? {
enabled: true,
level: LogLevel.DEBUG,
}
: {
enabled: true,
level: LogLevel.ERROR,
},
}}
>

Debug Mode Override

Force enable logging in any environment by setting a global flag:

// In browser console or your app
window.__GRAZ_DEBUG__ = true;

This bypasses all configuration and enables logging at all levels and categories.

Browser Console Features

Logs appear with colored formatting for easy identification:

  • 🟣 [graz] - Purple prefix
  • 🔴 ERROR - Red
  • 🟡 WARN - Orange
  • 🔵 INFO - Blue
  • DEBUG - Cyan
  • 🟢 [category] - Category-specific colors
  • 🎨 [function/hook] - Unique colors per function/hook

Each log includes structured data that can be expanded in the console for detailed inspection.

Troubleshooting

Logs not appearing?

  1. ✅ Check enabled: true is set
  2. ✅ Verify log level includes desired logs
  3. ✅ Check categories filter (use undefined for all)
  4. ✅ Open browser console
  5. ✅ Try window.__GRAZ_DEBUG__ = true

Too many logs?

  1. Reduce log level: LogLevel.INFO or LogLevel.ERROR
  2. Filter categories: [LogCategory.WALLET]
  3. Disable in production: enabled: false

Want specific operations only?

// Only wallet connection issues
logger: {
enabled: true,
level: LogLevel.ERROR,
categories: [LogCategory.WALLET]
}

// Only transaction logs
logger: {
enabled: true,
categories: [LogCategory.TRANSACTION]
}

Best Practices

1. Use Environment-based Configuration

const loggerConfig = process.env.NODE_ENV === "development"
? { enabled: true, level: LogLevel.DEBUG }
: { enabled: true, level: LogLevel.ERROR, errorReporter };

2. Filter by Category in Development

Instead of disabling logs, filter to relevant categories:

// When debugging wallet issues
logger: {
enabled: true,
categories: [LogCategory.WALLET, LogCategory.EVENT]
}

3. Always Enable Error Logging in Production

// Catch production errors without verbose logs
logger: {
enabled: true,
level: LogLevel.ERROR,
errorReporter: sentryReporter
}

4. Use Debug Mode for Deep Investigation

When users report issues, ask them to enable debug mode:

window.__GRAZ_DEBUG__ = true;
// Then reproduce the issue

5. Monitor Performance in Development

Keep an eye on performance logs for optimization opportunities:

logger: {
enabled: true,
categories: [LogCategory.PERFORMANCE]
}

Example: Complete Setup

Here's a complete example with all features:

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { GrazProvider, LogLevel, LogCategory } from "graz";
import * as Sentry from "@sentry/react";

const queryClient = new QueryClient();

const isDevelopment = process.env.NODE_ENV === "development";

const errorReporter = {
captureException: (error: Error, context?: Record<string, unknown>) => {
Sentry.captureException(error, { extra: context });
},
};

export default function App() {
return (
<QueryClientProvider client={queryClient}>
<GrazProvider
grazOptions={{
chains: [cosmoshubChainInfo, osmosisChainInfo],
logger: isDevelopment
? {
// Development: Verbose logging
enabled: true,
level: LogLevel.DEBUG,
categories: undefined, // All categories
}
: {
// Production: Only errors with tracking
enabled: true,
level: LogLevel.ERROR,
errorReporter,
},
}}
>
<YourApp />
</GrazProvider>
</QueryClientProvider>
);
}

Next Steps