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.
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
| Configuration | Logger 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.
Recommended Configurations
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?
- ✅ Check
enabled: trueis set - ✅ Verify log level includes desired logs
- ✅ Check categories filter (use
undefinedfor all) - ✅ Open browser console
- ✅ Try
window.__GRAZ_DEBUG__ = true
Too many logs?
- Reduce log level:
LogLevel.INFOorLogLevel.ERROR - Filter categories:
[LogCategory.WALLET] - 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
- Explore Performance Optimization for tips on improving your app
- Learn about Multi-chain Support and how it's logged
- Check out the Migration Guide for breaking changes