or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

common.mdexporters.mdindex.mdlogging.mdmetrics-stats.mdtags-context.mdtracing.md

logging.mddocs/

0

# Logging Integration

1

2

Integration with Python's logging system to automatically include trace context in log records, enabling correlation between logs and traces for better observability and debugging.

3

4

## Capabilities

5

6

### Log Context Extraction

7

8

Extract current OpenCensus trace context for inclusion in log records and correlation with distributed traces.

9

10

```python { .api }

11

def get_log_attrs():

12

"""

13

Get logging attributes from OpenCensus context.

14

15

Returns:

16

LogAttrs: Named tuple with trace_id, span_id, and sampling_decision

17

or ATTR_DEFAULTS if no context available

18

"""

19

20

LogAttrs = namedtuple('LogAttrs', ['trace_id', 'span_id', 'sampling_decision'])

21

"""

22

Named tuple containing trace context for logging.

23

24

Fields:

25

- trace_id: str, 32-character hex trace ID or default

26

- span_id: str, 16-character hex span ID or default

27

- sampling_decision: bool, whether trace is sampled

28

"""

29

30

ATTR_DEFAULTS = LogAttrs("00000000000000000000000000000000", "0000000000000000", False)

31

"""Default log attributes when no trace context is available."""

32

```

33

34

### Enhanced Logger Adapter

35

36

Logging adapter that automatically adds OpenCensus trace context to all log records for correlation and filtering.

37

38

```python { .api }

39

class TraceLoggingAdapter:

40

"""

41

LoggerAdapter that adds OpenCensus context to log records.

42

43

Inherits from logging.LoggerAdapter and automatically includes

44

trace context in all log messages.

45

46

Parameters:

47

- logger: logging.Logger, underlying logger instance

48

- extra: dict, additional context to include in logs

49

"""

50

def __init__(self, logger, extra=None): ...

51

52

def process(self, msg, kwargs):

53

"""

54

Process log message and add trace context.

55

56

Automatically adds current trace context to the log record's

57

extra data for correlation with distributed traces.

58

59

Parameters:

60

- msg: str, log message

61

- kwargs: dict, keyword arguments for logging call

62

63

Returns:

64

tuple: (processed_message, updated_kwargs)

65

"""

66

```

67

68

### Context-Aware Logger

69

70

Custom logger class that automatically includes OpenCensus trace context in log record creation.

71

72

```python { .api }

73

class TraceLogger:

74

"""

75

Logger subclass that includes OpenCensus context in records.

76

77

Inherits from logging.getLoggerClass() and automatically adds

78

trace context to all log records at creation time.

79

"""

80

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

81

"""

82

Create log record with OpenCensus trace context.

83

84

Extends standard makeRecord to automatically include current

85

trace context in the log record's attributes.

86

87

Parameters:

88

- *args: positional arguments for standard makeRecord

89

- **kwargs: keyword arguments for standard makeRecord

90

91

Returns:

92

LogRecord: Enhanced log record with trace context

93

"""

94

```

95

96

### Log Context Constants

97

98

Standard field names and default values for trace context in log records.

99

100

```python { .api }

101

TRACE_ID_KEY = 'traceId'

102

"""str: Log record field name for trace ID"""

103

104

SPAN_ID_KEY = 'spanId'

105

"""str: Log record field name for span ID"""

106

107

SAMPLING_DECISION_KEY = 'traceSampled'

108

"""str: Log record field name for sampling decision"""

109

```

110

111

## Usage Examples

112

113

### Basic Trace Logging Adapter

114

115

```python

116

import logging

117

from opencensus.log import TraceLoggingAdapter, get_log_attrs

118

from opencensus.trace.tracer import Tracer

119

120

# Set up standard logger

121

logger = logging.getLogger(__name__)

122

logger.setLevel(logging.INFO)

123

124

# Create handler with formatter that includes trace fields

125

handler = logging.StreamHandler()

126

formatter = logging.Formatter(

127

'%(asctime)s - %(name)s - %(levelname)s - '

128

'TraceID=%(traceId)s SpanID=%(spanId)s - %(message)s'

129

)

130

handler.setFormatter(formatter)

131

logger.addHandler(handler)

132

133

# Wrap with trace logging adapter

134

trace_logger = TraceLoggingAdapter(logger)

135

136

# Use within traced operations

137

tracer = Tracer()

138

139

with tracer.span('process_order') as span:

140

span.add_attribute('order_id', '12345')

141

142

# Log messages automatically include trace context

143

trace_logger.info('Starting order processing')

144

145

try:

146

# Process order logic

147

process_order_data()

148

trace_logger.info('Order processed successfully')

149

150

except Exception as e:

151

trace_logger.error('Order processing failed', exc_info=True)

152

raise

153

154

# Log output will include trace ID and span ID:

155

# 2024-01-15 10:30:15 - __main__ - INFO - TraceID=abc123... SpanID=def456... - Starting order processing

156

```

157

158

### Custom Logger Integration

159

160

```python

161

import logging

162

from opencensus.log import TraceLogger, get_log_attrs

163

164

# Set TraceLogger as default logger class

165

logging.setLoggerClass(TraceLogger)

166

167

# Create logger - will automatically include trace context

168

logger = logging.getLogger(__name__)

169

170

# Configure with trace-aware formatting

171

handler = logging.StreamHandler()

172

formatter = logging.Formatter(

173

'%(levelname)s [%(traceId)s:%(spanId)s] %(name)s: %(message)s'

174

)

175

handler.setFormatter(formatter)

176

logger.addHandler(handler)

177

logger.setLevel(logging.DEBUG)

178

179

from opencensus.trace.tracer import Tracer

180

181

def process_user_request(user_id):

182

tracer = Tracer()

183

184

with tracer.span('process_user_request') as span:

185

span.add_attribute('user_id', user_id)

186

187

# All log calls automatically include trace context

188

logger.info(f'Processing request for user {user_id}')

189

190

with tracer.span('validate_user') as child_span:

191

logger.debug('Validating user credentials')

192

validate_user(user_id)

193

logger.debug('User validation completed')

194

195

with tracer.span('load_user_data') as child_span:

196

logger.debug('Loading user data from database')

197

user_data = load_user_data(user_id)

198

logger.info(f'Loaded {len(user_data)} records for user')

199

200

logger.info('Request processing completed')

201

202

# Usage

203

process_user_request('user123')

204

```

205

206

### Manual Context Extraction

207

208

```python

209

import logging

210

from opencensus.log import get_log_attrs, TRACE_ID_KEY, SPAN_ID_KEY, SAMPLING_DECISION_KEY

211

212

# Standard logger setup

213

logger = logging.getLogger(__name__)

214

215

def custom_log_with_trace(level, message, **kwargs):

216

"""Custom logging function that manually adds trace context."""

217

218

# Get current trace context

219

trace_attrs = get_log_attrs()

220

221

# Add trace context to extra data

222

extra = kwargs.get('extra', {})

223

extra.update({

224

TRACE_ID_KEY: trace_attrs.trace_id,

225

SPAN_ID_KEY: trace_attrs.span_id,

226

SAMPLING_DECISION_KEY: trace_attrs.sampling_decision

227

})

228

229

# Log with enhanced context

230

logger.log(level, message, extra=extra, **kwargs)

231

232

# Usage within traced context

233

from opencensus.trace.tracer import Tracer

234

235

tracer = Tracer()

236

with tracer.span('database_operation') as span:

237

custom_log_with_trace(logging.INFO, 'Executing database query')

238

239

# Check if we have active trace context

240

attrs = get_log_attrs()

241

if attrs.trace_id != "00000000000000000000000000000000":

242

logger.info('Active trace detected', extra={

243

TRACE_ID_KEY: attrs.trace_id,

244

SPAN_ID_KEY: attrs.span_id

245

})

246

else:

247

logger.info('No active trace context')

248

```

249

250

### Structured Logging with Trace Context

251

252

```python

253

import logging

254

import json

255

from opencensus.log import TraceLoggingAdapter, get_log_attrs

256

257

class StructuredTraceFormatter(logging.Formatter):

258

"""JSON formatter that includes OpenCensus trace context."""

259

260

def format(self, record):

261

# Get trace context

262

trace_attrs = get_log_attrs()

263

264

# Build structured log entry

265

log_entry = {

266

'timestamp': self.formatTime(record),

267

'level': record.levelname,

268

'logger': record.name,

269

'message': record.getMessage(),

270

'trace': {

271

'trace_id': trace_attrs.trace_id,

272

'span_id': trace_attrs.span_id,

273

'sampled': trace_attrs.sampling_decision

274

}

275

}

276

277

# Add exception info if present

278

if record.exc_info:

279

log_entry['exception'] = self.formatException(record.exc_info)

280

281

# Add any extra fields

282

for key, value in record.__dict__.items():

283

if key not in ['name', 'levelname', 'levelno', 'pathname', 'filename',

284

'module', 'lineno', 'funcName', 'created', 'msecs',

285

'relativeCreated', 'thread', 'threadName', 'processName',

286

'process', 'getMessage', 'exc_info', 'exc_text', 'stack_info',

287

'args', 'msg']:

288

log_entry[key] = value

289

290

return json.dumps(log_entry)

291

292

# Setup structured logging with trace context

293

logger = logging.getLogger(__name__)

294

handler = logging.StreamHandler()

295

handler.setFormatter(StructuredTraceFormatter())

296

logger.addHandler(handler)

297

logger.setLevel(logging.INFO)

298

299

# Use with trace adapter

300

trace_logger = TraceLoggingAdapter(logger)

301

302

from opencensus.trace.tracer import Tracer

303

304

tracer = Tracer()

305

with tracer.span('api_request') as span:

306

span.add_attribute('endpoint', '/api/users')

307

span.add_attribute('method', 'GET')

308

309

# Structured log with automatic trace context

310

trace_logger.info('API request received', extra={

311

'endpoint': '/api/users',

312

'method': 'GET',

313

'user_agent': 'OpenCensus/1.0'

314

})

315

316

# Output will be JSON with embedded trace context:

317

# {"timestamp": "2024-01-15 10:30:15,123", "level": "INFO",

318

# "logger": "__main__", "message": "API request received",

319

# "trace": {"trace_id": "abc123...", "span_id": "def456...", "sampled": true},

320

# "endpoint": "/api/users", "method": "GET", "user_agent": "OpenCensus/1.0"}

321

```

322

323

### Integration with Application Frameworks

324

325

```python

326

import logging

327

from opencensus.log import TraceLoggingAdapter

328

from opencensus.trace.tracer import Tracer

329

from opencensus.trace.propagation import trace_context_http_header_format

330

331

# Flask example

332

from flask import Flask, request, g

333

334

app = Flask(__name__)

335

336

# Setup trace-aware logging

337

logging.basicConfig(level=logging.INFO)

338

logger = logging.getLogger(__name__)

339

trace_logger = TraceLoggingAdapter(logger)

340

341

@app.before_request

342

def before_request():

343

# Extract trace context from incoming request

344

propagator = trace_context_http_header_format.TraceContextPropagator()

345

span_context = propagator.from_headers(request.headers)

346

347

# Create tracer with incoming context

348

g.tracer = Tracer(span_context=span_context)

349

g.span = g.tracer.span(f'{request.method} {request.path}')

350

g.span.start()

351

352

# Log request with trace context

353

trace_logger.info(f'Incoming request: {request.method} {request.path}',

354

extra={'method': request.method, 'path': request.path})

355

356

@app.after_request

357

def after_request(response):

358

# Log response with trace context

359

trace_logger.info(f'Response status: {response.status_code}',

360

extra={'status_code': response.status_code})

361

362

if hasattr(g, 'span'):

363

g.span.add_attribute('http.status_code', response.status_code)

364

g.span.finish()

365

366

return response

367

368

@app.route('/api/users/<user_id>')

369

def get_user(user_id):

370

# All log messages within request automatically have trace context

371

trace_logger.info(f'Fetching user data for {user_id}')

372

373

with g.tracer.span('database_query') as span:

374

span.add_attribute('user_id', user_id)

375

trace_logger.debug('Executing database query')

376

377

# Simulate database operation

378

user_data = {'id': user_id, 'name': 'John Doe'}

379

380

trace_logger.info('User data retrieved successfully')

381

382

return user_data

383

384

if __name__ == '__main__':

385

app.run(debug=True)

386

```