or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bound-loggers.mdconfiguration.mdcontext-management.mddevelopment-tools.mdexception-handling.mdindex.mdlogger-creation.mdoutput-loggers.mdprocessors.mdstdlib-integration.mdtesting.md

bound-loggers.mddocs/

0

# Bound Logger Classes

1

2

Immutable context-carrying logger classes that provide the core structlog API. Bound loggers maintain context data and delegate logging operations to wrapped loggers while supporting context binding, unbinding, and transformation operations.

3

4

## Capabilities

5

6

### Base Bound Logger

7

8

Base class for all bound loggers providing core context manipulation and event processing functionality.

9

10

```python { .api }

11

class BoundLoggerBase:

12

"""

13

Base class for immutable context carriers.

14

15

Provides core functionality for context binding, unbinding, and event processing.

16

All bound logger implementations inherit from this class.

17

"""

18

19

def __init__(self, logger, processors, context): ...

20

21

def bind(self, **new_values) -> Self:

22

"""

23

Return new bound logger with additional context values.

24

25

Args:

26

**new_values: Key-value pairs to add to the context

27

28

Returns:

29

New bound logger instance with merged context

30

"""

31

32

def unbind(self, *keys) -> Self:

33

"""

34

Return new bound logger with specified keys removed from context.

35

36

Args:

37

*keys: Context keys to remove

38

39

Returns:

40

New bound logger instance with keys removed

41

42

Raises:

43

KeyError: If any key is not found in context

44

"""

45

46

def try_unbind(self, *keys) -> Self:

47

"""

48

Return new bound logger with specified keys removed, ignoring missing keys.

49

50

Args:

51

*keys: Context keys to remove

52

53

Returns:

54

New bound logger instance with existing keys removed

55

"""

56

57

def new(self, **new_values) -> Self:

58

"""

59

Return new bound logger with cleared context and new values.

60

61

Args:

62

**new_values: Key-value pairs for the new context

63

64

Returns:

65

New bound logger instance with only the specified context

66

"""

67

68

def _process_event(self, method_name, event, event_kw) -> tuple[Sequence[Any], Mapping[str, Any]]:

69

"""Process event through processor chain (protected method)."""

70

71

def _proxy_to_logger(self, method_name, event=None, **event_kw) -> Any:

72

"""Proxy method call to wrapped logger (protected method)."""

73

```

74

75

### Generic Bound Logger

76

77

Generic bound logger that can wrap any logger and provides dynamic method delegation.

78

79

```python { .api }

80

class BoundLogger(BoundLoggerBase):

81

"""

82

Generic bound logger that can wrap anything.

83

84

Uses dynamic method delegation to forward all method calls

85

to the wrapped logger after processing through the processor chain.

86

"""

87

```

88

89

### Context Utilities

90

91

Functions for working with bound logger contexts.

92

93

```python { .api }

94

def get_context(bound_logger) -> Context:

95

"""

96

Return the context dictionary from a bound logger.

97

98

Args:

99

bound_logger: Bound logger instance

100

101

Returns:

102

dict: Copy of the logger's context

103

"""

104

```

105

106

## Usage Examples

107

108

### Basic Context Binding

109

110

```python

111

import structlog

112

113

structlog.configure(

114

processors=[structlog.processors.JSONRenderer()],

115

wrapper_class=structlog.BoundLogger,

116

)

117

118

logger = structlog.get_logger()

119

120

# Bind context values

121

user_logger = logger.bind(user_id=123, username="alice")

122

user_logger.info("User logged in")

123

124

# Bind additional context

125

session_logger = user_logger.bind(session_id="abc-def", ip="192.168.1.1")

126

session_logger.info("Session created")

127

128

# Original logger is unchanged

129

logger.info("System message") # No user context

130

```

131

132

### Context Unbinding

133

134

```python

135

import structlog

136

137

logger = structlog.get_logger()

138

rich_logger = logger.bind(

139

user_id=123,

140

session_id="abc-def",

141

request_id="req-456",

142

debug_info="temp"

143

)

144

145

# Remove specific keys

146

clean_logger = rich_logger.unbind("debug_info")

147

clean_logger.info("Cleaned up") # No debug_info

148

149

# Remove multiple keys

150

minimal_logger = rich_logger.unbind("debug_info", "request_id")

151

minimal_logger.info("Minimal context") # Only user_id and session_id

152

153

# try_unbind ignores missing keys

154

safe_logger = rich_logger.try_unbind("missing_key", "debug_info")

155

safe_logger.info("Safe unbind") # No error for missing_key

156

```

157

158

### Context Replacement

159

160

```python

161

import structlog

162

163

logger = structlog.get_logger()

164

request_logger = logger.bind(

165

user_id=123,

166

session_id="old-session",

167

request_id="req-1"

168

)

169

170

# Clear all context and start fresh

171

new_request_logger = request_logger.new(

172

user_id=456,

173

request_id="req-2",

174

endpoint="/api/orders"

175

)

176

177

new_request_logger.info("New request started") # Only new context

178

```

179

180

### Working with Context

181

182

```python

183

import structlog

184

185

logger = structlog.get_logger()

186

context_logger = logger.bind(service="auth", version="1.2.3")

187

188

# Get the current context

189

context = structlog.get_context(context_logger)

190

print(context) # {'service': 'auth', 'version': '1.2.3'}

191

192

# Use context for conditional logic

193

if context.get("service") == "auth":

194

enhanced_logger = context_logger.bind(auth_enabled=True)

195

enhanced_logger.info("Authentication service ready")

196

```

197

198

### Chaining Context Operations

199

200

```python

201

import structlog

202

203

logger = structlog.get_logger()

204

205

# Chain multiple context operations

206

request_logger = (logger

207

.bind(request_id="req-789")

208

.bind(user_id=123, ip="10.0.0.1")

209

.unbind("ip") # Remove IP for privacy

210

.bind(anonymized=True)

211

)

212

213

request_logger.info("Request processed")

214

```

215

216

### Custom Context Classes

217

218

```python

219

import structlog

220

from collections import UserDict

221

222

class CustomContext(UserDict):

223

def __init__(self, *args, **kwargs):

224

super().__init__(*args, **kwargs)

225

self.access_count = 0

226

227

def __getitem__(self, key):

228

self.access_count += 1

229

return super().__getitem__(key)

230

231

structlog.configure(

232

processors=[structlog.processors.JSONRenderer()],

233

wrapper_class=structlog.BoundLogger,

234

context_class=CustomContext,

235

)

236

237

logger = structlog.get_logger()

238

tracked_logger = logger.bind(user_id=123)

239

tracked_logger.info("Tracking access")

240

```

241

242

### Error Handling in Context Operations

243

244

```python

245

import structlog

246

247

logger = structlog.get_logger()

248

context_logger = logger.bind(user_id=123, session_id="abc")

249

250

try:

251

# This will raise KeyError

252

broken_logger = context_logger.unbind("missing_key")

253

except KeyError:

254

# Use try_unbind instead

255

safe_logger = context_logger.try_unbind("missing_key")

256

safe_logger.info("Handled missing key gracefully")

257

258

# Alternative: check context first

259

context = structlog.get_context(context_logger)

260

if "session_id" in context:

261

clean_logger = context_logger.unbind("session_id")

262

clean_logger.info("Session cleaned up")

263

```