Skip to content

Commit 091808f

Browse files
committed
add post
1 parent af2cb60 commit 091808f

1 file changed

Lines changed: 130 additions & 0 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
layout: post
3+
title: "[Swift][Xcode 15] 통합 로깅 시스템(Unified Logging System)과 Macro"
4+
tags: [Swift, Xcode, Logger, Debug, Log, OSLog]
5+
---
6+
{% include JB/setup %}
7+
8+
Swift 통합 로깅 시스템(Unified Logging System)은 iOS, macOS, watchOS, tvOS 등 모든 Apple 플랫폼에서 일관되게 로그를 기록하고 관리하는 시스템입니다.
9+
10+
WWDC 2023의 ["Debug with structured logging" 세션](https://developer.apple.com/videos/play/wwdc2023/10226/)에서 콘솔 로그에 상세한 정보를 추가하는 방법을 소개하였습니다. 기존 print(), NSLog 등과 달리 구조화된 로그를 남길 수 있습니다.
11+
12+
<p style="text-align:center;"><img src="{{ site.prod_url }}/image/2024/03/01.png" style="border: 1px solid #555;"/></p><br/>
13+
14+
위 화면에서 콘솔 로그를 살펴보면 로그 레벨, 메시지 등을 표시하고, 오른쪽에는 Logger 호출 위치를 확인할 수 있으며, 화살표를 눌러 해당 코드로 이동할 수 있습니다. 이 기능은 로그 출력 위치를 빠르게 찾아 디버깅에 유용합니다.
15+
16+
하지만, 다음과 같이 Logger를 감싸서 호출하면 이 기능을 사용할 수 없게 됩니다.
17+
18+
```swift
19+
import OSLog
20+
21+
struct WrapperLogger {
22+
func debug(msg: String) {
23+
let logger = Logger(subsystem: "kr.minsone.feature.logger", category: "debug")
24+
logger.log(level: .debug, "\(msg)")
25+
}
26+
}
27+
28+
let logger = WrapperLogger()
29+
logger.debug(msg: "Hello World")
30+
```
31+
32+
<p style="text-align:center;"><img src="{{ site.prod_url }}/image/2024/03/02.png" style="border: 1px solid #555;"/></p><br/>
33+
34+
추상화된 코드 위치가 아닌 실제 Logger 호출 위치를 표시하고 있습니다. Xcode 15 버전에서는 이 문제를 해결할 수 있는 방법이 없습니다.
35+
36+
추상화하지 않는다면, 매번 Logger를 만들거나 전역으로 선언해야하는데, 이는 매 작업시 불편함을 유발하므로, 자동으로 코드를 만들어주는 방법이 필요합니다.
37+
38+
Xcode 15부터 Swift 5.9를 지원하고, Swift 5.9에서는 Swift Macro를 지원합니다. Swift Macro를 이용한다면 매번 작성해야하는 Logger를 생성하는 코드를 생성할 수 있지 않을까요?
39+
40+
## Swift Macro
41+
42+
Swift Macro에 `@attached(member)`를 사용하면 매크로를 적용하는 코드에 별도의 속성을 추가할 수 있습니다. 즉, `Logger`를 만들 수 있습니다.
43+
44+
Logger 생성 매크로를 만들어봅시다.
45+
46+
```swift
47+
/// Module : LoggingMacros
48+
/// FileName : LoggingMacro.swift
49+
50+
import SwiftSyntax
51+
import SwiftSyntaxBuilder
52+
import SwiftSyntaxMacroExpansion
53+
import SwiftSyntaxMacros
54+
55+
public struct LoggingMacro: MemberMacro {
56+
public static func expansion(
57+
of node: AttributeSyntax,
58+
providingMembersOf declaration: some DeclGroupSyntax,
59+
in context: some MacroExpansionContext) throws -> [DeclSyntax] {
60+
let allowTypes: [SyntaxKind] = [
61+
.classDecl,
62+
.structDecl,
63+
.actorDecl,
64+
]
65+
66+
guard allowTypes.contains(declaration.kind) else {
67+
let msg = "@Logger는 Class, Struct, Actor에만 사용 가능합니다."
68+
throw MacroExpansionErrorMessage(msg)
69+
}
70+
71+
return [
72+
DeclSyntax(
73+
#"""
74+
lazy var logger: Logger = {
75+
LoggingMacroHelper.generateLogger(category: String(describing: Self.self))
76+
}()
77+
"""#),
78+
]
79+
}
80+
}
81+
82+
/// Module : Logging
83+
/// FileName : MemberMacros.swift
84+
85+
import Foundation
86+
@_exported import OSLog
87+
88+
@attached(member, names: named(logger))
89+
public macro Logging() = #externalMacro(module: "LoggingMacros", type: "LoggingMacro")
90+
91+
// MARK: - Helper
92+
93+
public enum LoggingMacroHelper {
94+
public static func generateLogger(_ fileID: String = #fileID, category: String) -> Logger {
95+
let subsystem = fileID.components(separatedBy: "/").first.map { "kr.minsone.\($0)" }
96+
return subsystem.map { Logger(subsystem: $0, category: category) }
97+
?? Logger()
98+
}
99+
}
100+
101+
```
102+
103+
위와 같이 매크로를 작성한 뒤, 다음과 같이 사용할 수 있습니다.
104+
105+
```swift
106+
/// FileName : Example.swift
107+
108+
@Logging
109+
class ABC {
110+
func sendLog() {
111+
logger.log(level: .debug, "\(Self.self) \(#function), log")
112+
}
113+
}
114+
115+
ABC().sendLog() // Output : ABC sendLog(), log
116+
```
117+
118+
<p style="text-align:center;"><img src="{{ site.prod_url }}/image/2024/03/03.png" style="border: 1px solid #555;"/></p><br/>
119+
120+
## 정리
121+
122+
* Swift Macro를 이용하여 Logger를 생성하고, 쉽게 사용할 수 있음
123+
124+
## 참고자료
125+
126+
* Apple
127+
* WWDC 2023 - [Debug with structured logging](https://developer.apple.com/videos/play/wwdc2023/10226/)
128+
129+
* GitHub
130+
* [JamesSedlacek/Logging](https://github.com/JamesSedlacek/Logging)

0 commit comments

Comments
 (0)