or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

arguments.mdcaching.mdconfiguration.mdcontrollers.mdextensions.mdfoundation.mdhooks.mdindex.mdinterface-handler.mdlogging.mdmail.mdoutput.mdplugins.mdtemplates.mdutilities.md

logging.mddocs/

0

# Logging System

1

2

The logging system provides comprehensive logging functionality with console and file output support, multiple log levels, colorized output options, and integration with Python's standard logging module.

3

4

## Capabilities

5

6

### Log Handler Interface

7

8

Base interface for logging functionality that defines the contract for logging operations.

9

10

```python { .api }

11

class LogHandler:

12

"""

13

Logging handler interface for application logging functionality.

14

15

Provides methods for logging at different levels and controlling

16

log output configuration and formatting.

17

"""

18

19

def set_level(self, level: str) -> None:

20

"""

21

Set the logging level.

22

23

Args:

24

level: Logging level ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')

25

"""

26

27

def get_level(self) -> str:

28

"""

29

Get the current logging level.

30

31

Returns:

32

Current logging level string

33

"""

34

35

def debug(self, msg: str, **kwargs: Any) -> None:

36

"""

37

Log a debug message.

38

39

Args:

40

msg: Message to log

41

**kwargs: Additional keyword arguments for formatting

42

"""

43

44

def info(self, msg: str, **kwargs: Any) -> None:

45

"""

46

Log an info message.

47

48

Args:

49

msg: Message to log

50

**kwargs: Additional keyword arguments for formatting

51

"""

52

53

def warning(self, msg: str, **kwargs: Any) -> None:

54

"""

55

Log a warning message.

56

57

Args:

58

msg: Message to log

59

**kwargs: Additional keyword arguments for formatting

60

"""

61

62

def error(self, msg: str, **kwargs: Any) -> None:

63

"""

64

Log an error message.

65

66

Args:

67

msg: Message to log

68

**kwargs: Additional keyword arguments for formatting

69

"""

70

71

def fatal(self, msg: str, **kwargs: Any) -> None:

72

"""

73

Log a fatal/critical message.

74

75

Args:

76

msg: Message to log

77

**kwargs: Additional keyword arguments for formatting

78

"""

79

```

80

81

## Usage Examples

82

83

### Basic Logging

84

85

```python

86

from cement import App, Controller, ex

87

88

class BaseController(Controller):

89

class Meta:

90

label = 'base'

91

92

@ex(help='demonstrate logging')

93

def demo(self):

94

"""Demonstrate different logging levels."""

95

self.app.log.debug('This is a debug message')

96

self.app.log.info('Application started successfully')

97

self.app.log.warning('This is a warning message')

98

self.app.log.error('An error occurred')

99

100

try:

101

# Simulate an operation that might fail

102

result = 10 / 0

103

except ZeroDivisionError:

104

self.app.log.error('Division by zero error occurred')

105

106

class MyApp(App):

107

class Meta:

108

label = 'myapp'

109

base_controller = 'base'

110

handlers = [BaseController]

111

112

with MyApp() as app:

113

app.setup()

114

115

# Set logging level

116

app.log.set_level('DEBUG')

117

118

app.run()

119

```

120

121

### File Logging Configuration

122

123

```python

124

from cement import App, init_defaults

125

126

CONFIG = init_defaults('myapp')

127

CONFIG['log.logging'] = {

128

'file': '/var/log/myapp.log',

129

'level': 'INFO',

130

'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',

131

'rotate': True,

132

'max_bytes': 1024000, # 1MB

133

'max_files': 5

134

}

135

136

class MyApp(App):

137

class Meta:

138

label = 'myapp'

139

config_defaults = CONFIG

140

log_handler = 'logging'

141

142

with MyApp() as app:

143

app.setup()

144

145

app.log.info('Application started')

146

app.log.debug('Debug information')

147

app.log.warning('Warning message')

148

149

app.run()

150

```

151

152

### Colorized Logging

153

154

```python

155

from cement import App, init_defaults

156

157

CONFIG = init_defaults('myapp')

158

CONFIG['log.colorlog'] = {

159

'level': 'DEBUG',

160

'format': '%(log_color)s%(levelname)s%(reset)s - %(message)s',

161

'colors': {

162

'DEBUG': 'cyan',

163

'INFO': 'green',

164

'WARNING': 'yellow',

165

'ERROR': 'red',

166

'CRITICAL': 'bold_red'

167

}

168

}

169

170

class MyApp(App):

171

class Meta:

172

label = 'myapp'

173

extensions = ['colorlog']

174

log_handler = 'colorlog'

175

config_defaults = CONFIG

176

177

with MyApp() as app:

178

app.setup()

179

180

app.log.debug('Debug message in cyan')

181

app.log.info('Info message in green')

182

app.log.warning('Warning message in yellow')

183

app.log.error('Error message in red')

184

185

app.run()

186

```

187

188

### Custom Logging Configuration

189

190

```python

191

from cement import App, Controller, ex

192

import logging

193

194

class LoggingController(Controller):

195

class Meta:

196

label = 'logging'

197

stacked_on = 'base'

198

stacked_type = 'nested'

199

200

@ex(

201

help='set logging level',

202

arguments=[

203

(['level'], {

204

'choices': ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],

205

'help': 'logging level to set'

206

})

207

]

208

)

209

def set_level(self):

210

"""Set the logging level."""

211

level = self.app.pargs.level

212

self.app.log.set_level(level)

213

self.app.log.info(f'Logging level set to {level}')

214

215

@ex(help='show current logging level')

216

def get_level(self):

217

"""Show current logging level."""

218

level = self.app.log.get_level()

219

print(f'Current logging level: {level}')

220

221

@ex(help='test all logging levels')

222

def test(self):

223

"""Test all logging levels."""

224

self.app.log.debug('Debug level message')

225

self.app.log.info('Info level message')

226

self.app.log.warning('Warning level message')

227

self.app.log.error('Error level message')

228

self.app.log.fatal('Fatal level message')

229

230

class BaseController(Controller):

231

class Meta:

232

label = 'base'

233

234

class MyApp(App):

235

class Meta:

236

label = 'myapp'

237

base_controller = 'base'

238

handlers = [

239

BaseController,

240

LoggingController

241

]

242

243

with MyApp() as app:

244

app.run()

245

246

# Usage:

247

# myapp logging set-level DEBUG

248

# myapp logging get-level

249

# myapp logging test

250

```

251

252

### Structured Logging

253

254

```python

255

from cement import App, Controller, ex

256

import json

257

import logging

258

259

class StructuredLogHandler(logging.Handler):

260

"""Custom handler for structured JSON logging."""

261

262

def emit(self, record):

263

log_entry = {

264

'timestamp': self.format_time(record),

265

'level': record.levelname,

266

'message': record.getMessage(),

267

'module': record.module,

268

'function': record.funcName,

269

'line': record.lineno

270

}

271

272

# Add extra fields if present

273

if hasattr(record, 'user_id'):

274

log_entry['user_id'] = record.user_id

275

if hasattr(record, 'request_id'):

276

log_entry['request_id'] = record.request_id

277

278

print(json.dumps(log_entry))

279

280

def format_time(self, record):

281

import datetime

282

return datetime.datetime.fromtimestamp(record.created).isoformat()

283

284

class BaseController(Controller):

285

class Meta:

286

label = 'base'

287

288

@ex(help='demonstrate structured logging')

289

def structured_demo(self):

290

"""Demonstrate structured logging with extra fields."""

291

# Log with extra context

292

extra = {

293

'user_id': 'user_123',

294

'request_id': 'req_456'

295

}

296

297

self.app.log.info('User login attempt', extra=extra)

298

self.app.log.warning('Invalid login credentials', extra=extra)

299

self.app.log.error('Database connection failed', extra=extra)

300

301

class MyApp(App):

302

class Meta:

303

label = 'myapp'

304

base_controller = 'base'

305

handlers = [BaseController]

306

307

def setup(self):

308

super().setup()

309

310

# Add structured logging handler

311

structured_handler = StructuredLogHandler()

312

self.log.logger.addHandler(structured_handler)

313

314

with MyApp() as app:

315

app.run()

316

```

317

318

### Logging with Context Managers

319

320

```python

321

from cement import App, Controller, ex

322

import contextlib

323

import time

324

325

@contextlib.contextmanager

326

def log_execution_time(logger, operation_name):

327

"""Context manager to log operation execution time."""

328

start_time = time.time()

329

logger.info(f'Starting {operation_name}')

330

331

try:

332

yield

333

execution_time = time.time() - start_time

334

logger.info(f'Completed {operation_name} in {execution_time:.2f} seconds')

335

except Exception as e:

336

execution_time = time.time() - start_time

337

logger.error(f'Failed {operation_name} after {execution_time:.2f} seconds: {e}')

338

raise

339

340

class BaseController(Controller):

341

class Meta:

342

label = 'base'

343

344

@ex(help='demonstrate logging with context manager')

345

def timed_operation(self):

346

"""Demonstrate timed operation logging."""

347

with log_execution_time(self.app.log, 'data processing'):

348

# Simulate some work

349

time.sleep(2)

350

self.app.log.info('Processing data...')

351

time.sleep(1)

352

self.app.log.info('Data processing completed')

353

354

class MyApp(App):

355

class Meta:

356

label = 'myapp'

357

base_controller = 'base'

358

handlers = [BaseController]

359

360

with MyApp() as app:

361

app.run()

362

```

363

364

### Multiple Log Destinations

365

366

```python

367

from cement import App, init_defaults

368

import logging

369

import sys

370

371

CONFIG = init_defaults('myapp')

372

CONFIG['log.logging'] = {

373

'level': 'INFO',

374

'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

375

}

376

377

class MyApp(App):

378

class Meta:

379

label = 'myapp'

380

config_defaults = CONFIG

381

log_handler = 'logging'

382

383

def setup(self):

384

super().setup()

385

386

# Add file handler

387

file_handler = logging.FileHandler('/var/log/myapp.log')

388

file_formatter = logging.Formatter(

389

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

390

)

391

file_handler.setFormatter(file_formatter)

392

file_handler.setLevel(logging.INFO)

393

394

# Add console handler for errors only

395

error_handler = logging.StreamHandler(sys.stderr)

396

error_formatter = logging.Formatter(

397

'ERROR: %(message)s'

398

)

399

error_handler.setFormatter(error_formatter)

400

error_handler.setLevel(logging.ERROR)

401

402

# Add handlers to logger

403

self.log.logger.addHandler(file_handler)

404

self.log.logger.addHandler(error_handler)

405

406

with MyApp() as app:

407

app.setup()

408

409

app.log.info('This goes to file and console')

410

app.log.warning('This goes to file and console')

411

app.log.error('This goes to file, console, and stderr')

412

413

app.run()

414

```