or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-config.mdconfiguration.mdindex.mdlevels-formats.mdloggers.mdplatform-features.md

platform-features.mddocs/

0

# Platform-Specific Features

1

2

The Ktor Client Logging plugin provides platform-optimized implementations and features tailored to different runtime environments.

3

4

## Required Imports

5

6

```kotlin

7

import io.ktor.client.*

8

import io.ktor.client.plugins.logging.*

9

import kotlinx.coroutines.*

10

import org.slf4j.MDC // JVM only

11

import kotlin.coroutines.CoroutineContext

12

```

13

14

## JVM Platform Features

15

16

### SLF4J Integration

17

18

The JVM implementation seamlessly integrates with SLF4J, the standard logging facade for Java applications.

19

20

```kotlin { .api }

21

val Logger.Companion.DEFAULT: Logger

22

```

23

24

**JVM Implementation Details:**

25

- Uses `LoggerFactory.getLogger(HttpClient::class.java)`

26

- Logs at INFO level through SLF4J

27

- Respects your SLF4J configurations (logback.xml, log4j2.xml, etc.)

28

- Thread-safe for concurrent HTTP clients

29

30

**Configuration Example:**

31

```kotlin

32

// Inherits your SLF4J configuration

33

Logging {

34

logger = Logger.DEFAULT // Uses SLF4J

35

level = LogLevel.ALL

36

}

37

```

38

39

### Android Logcat Support

40

41

Special Android-optimized logger with Logcat integration and automatic message chunking.

42

43

```kotlin { .api }

44

val Logger.Companion.ANDROID: Logger

45

```

46

47

**Features:**

48

- **Automatic Logcat Detection**: Uses `android.util.Log` when available

49

- **SLF4J Fallback**: Falls back to SLF4J if Logcat is unavailable

50

- **Message Length Limiting**: Breaks long messages to fit Android's log constraints

51

- **Tag Management**: Uses "Ktor Client" as the log tag

52

- **Lazy Initialization**: Created on first access for optimal performance

53

54

**Android-Specific Behavior:**

55

- Maximum message length: 4000 characters

56

- Prefers newline breaks between 3000-4000 characters

57

- Graceful fallback if `android.util.Log` class not found

58

- Thread-safe for Android's multi-threaded environment

59

60

**Usage in Android Projects:**

61

```kotlin

62

val client = HttpClient {

63

install(Logging) {

64

logger = Logger.ANDROID

65

level = LogLevel.HEADERS

66

}

67

}

68

```

69

70

### MDC Context Propagation

71

72

Maintain Mapped Diagnostic Context (MDC) across coroutine boundaries for enhanced logging correlation.

73

74

```kotlin { .api }

75

// JVM Platform

76

actual fun MDCContext(): CoroutineContext.Element

77

78

// JavaScript/WASM Platform

79

actual fun MDCContext(): CoroutineContext.Element

80

81

// Native/Posix Platform

82

actual fun MDCContext(): CoroutineContext.Element

83

```

84

85

**Purpose:**

86

- Preserves SLF4J MDC context in coroutine-based HTTP operations

87

- Enables request correlation across async operations

88

- Supports structured logging and distributed tracing

89

90

**Usage with Coroutines:**

91

```kotlin

92

// Set up MDC context

93

MDC.put("requestId", "req-123")

94

MDC.put("userId", "user-456")

95

96

// Create client with MDC context preservation

97

val client = HttpClient {

98

install(Logging) {

99

logger = Logger.DEFAULT // Will include MDC context

100

level = LogLevel.INFO

101

}

102

}

103

104

// MDC context is automatically propagated through coroutines

105

runBlocking(MDCContext()) {

106

val response = client.get("https://api.example.com/data")

107

// Logs will include requestId and userId from MDC

108

}

109

```

110

111

**Integration with Structured Logging:**

112

```kotlin

113

// Example with logback-structured-config

114

MDC.put("traceId", UUID.randomUUID().toString())

115

MDC.put("operation", "user-creation")

116

117

val client = HttpClient {

118

install(Logging) {

119

logger = Logger.DEFAULT

120

level = LogLevel.ALL

121

filter { request ->

122

request.url.pathSegments.contains("users")

123

}

124

}

125

}

126

127

withContext(MDCContext()) {

128

// All HTTP logs will include traceId and operation

129

client.post("https://api.example.com/users") {

130

contentType(ContentType.Application.Json)

131

setBody(userCreateRequest)

132

}

133

}

134

```

135

136

## JavaScript/WASM Platform Features

137

138

### Console Integration

139

140

```kotlin { .api }

141

val Logger.Companion.DEFAULT: Logger // Points to Logger.SIMPLE

142

```

143

144

**Features:**

145

- Uses browser console or Node.js console

146

- Simple console.log implementation

147

- No additional dependencies

148

- Works in both browser and Node.js environments

149

150

**Browser Example:**

151

```kotlin

152

val client = HttpClient {

153

install(Logging) {

154

logger = Logger.DEFAULT // Uses console

155

level = LogLevel.INFO

156

}

157

}

158

```

159

160

## Native/Posix Platform Features

161

162

### Standard Output Integration

163

164

```kotlin { .api }

165

val Logger.Companion.DEFAULT: Logger // Points to Logger.SIMPLE

166

```

167

168

**Features:**

169

- Uses platform's standard output

170

- Minimal overhead implementation

171

- Compatible with native compilation

172

- Works across all supported native targets

173

174

## Platform-Specific Logger Selection

175

176

### Automatic Platform Detection

177

178

The `Logger.DEFAULT` implementation automatically selects the most appropriate logging mechanism for each platform:

179

180

```kotlin

181

// Same code works across all platforms

182

val client = HttpClient {

183

install(Logging) {

184

logger = Logger.DEFAULT

185

level = LogLevel.HEADERS

186

}

187

}

188

```

189

190

**Platform Mappings:**

191

- **JVM**: SLF4J-based logger with HttpClient class logger

192

- **Android**: Same as JVM (use `Logger.ANDROID` for Logcat)

193

- **JavaScript**: Browser console or Node.js console

194

- **WASM**: Browser console

195

- **Native**: Platform standard output

196

197

### Platform-Specific Optimizations

198

199

#### JVM Optimizations

200

```kotlin

201

val client = HttpClient {

202

install(Logging) {

203

// Leverage SLF4J configuration

204

logger = Logger.DEFAULT

205

206

// Use Android-specific features if needed

207

logger = Logger.ANDROID

208

209

// Or customize with message limiting

210

logger = MessageLengthLimitingLogger(

211

maxLength = 8000, // Higher limit for JVM

212

delegate = Logger.DEFAULT

213

)

214

215

level = LogLevel.ALL

216

}

217

}

218

```

219

220

#### Mobile/Android Optimizations

221

```kotlin

222

val client = HttpClient {

223

install(Logging) {

224

// Optimized for Android Logcat

225

logger = Logger.ANDROID

226

227

// Conservative logging to preserve performance/battery

228

level = LogLevel.INFO

229

format = LoggingFormat.OkHttp // More compact

230

231

// Filter to reduce log volume

232

filter { request ->

233

!request.url.host.contains("analytics") &&

234

!request.url.pathSegments.contains("ping")

235

}

236

}

237

}

238

```

239

240

#### Web/JavaScript Optimizations

241

```kotlin

242

val client = HttpClient {

243

install(Logging) {

244

logger = Logger.DEFAULT // Console logging

245

246

// Minimal logging for production builds

247

level = when (js("process.env.NODE_ENV")) {

248

"production" -> LogLevel.NONE

249

"development" -> LogLevel.ALL

250

else -> LogLevel.INFO

251

}

252

}

253

}

254

```

255

256

## Cross-Platform Compatibility

257

258

### Unified API

259

260

All platform-specific features maintain the same API surface:

261

262

```kotlin

263

// This code works identically across all platforms

264

class ApiClient {

265

private val client = HttpClient {

266

install(Logging) {

267

logger = Logger.DEFAULT // Platform-appropriate implementation

268

level = LogLevel.HEADERS

269

format = LoggingFormat.OkHttp

270

271

filter { request ->

272

request.url.host == "api.myapp.com"

273

}

274

275

sanitizeHeader { headerName ->

276

headerName.equals("Authorization", ignoreCase = true)

277

}

278

}

279

}

280

281

suspend fun fetchUser(id: String): User {

282

return client.get("https://api.myapp.com/users/$id").body()

283

}

284

}

285

```

286

287

### Platform Detection Example

288

289

```kotlin

290

val platformOptimizedClient = HttpClient {

291

install(Logging) {

292

// Platform-specific logger selection

293

logger = when (Platform.Current) {

294

is JvmPlatform -> if (isAndroid()) Logger.ANDROID else Logger.DEFAULT

295

is JsPlatform -> Logger.SIMPLE

296

is NativePlatform -> Logger.SIMPLE

297

}

298

299

// Platform-appropriate log levels

300

level = when (Platform.Current) {

301

is JvmPlatform -> LogLevel.ALL // JVM can handle verbose logging

302

else -> LogLevel.INFO // Mobile/web prefer less verbose

303

}

304

305

format = LoggingFormat.OkHttp // Compact format for all platforms

306

}

307

}

308

```

309

310

## Performance Considerations

311

312

### JVM Platform

313

- **SLF4J Overhead**: Minimal, delegates to configured logging framework

314

- **MDC Context**: Small overhead for context propagation

315

- **Message Limiting**: Optional, use only when needed

316

317

### Mobile Platforms

318

- **Battery Impact**: Use conservative log levels in production

319

- **Memory Usage**: Avoid `LogLevel.ALL` with large payloads

320

- **Performance**: Filter requests to reduce logging overhead

321

322

### Web Platforms

323

- **Bundle Size**: Logging adds minimal size overhead

324

- **Network Performance**: Consider filtering frequent requests

325

- **Development vs Production**: Use conditional logging levels