File: LocalLoggingTest.swift

package info (click to toggle)
swiftlang 6.1.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,791,532 kB
  • sloc: cpp: 9,901,743; ansic: 2,201,431; asm: 1,091,827; python: 308,252; objc: 82,166; f90: 80,126; lisp: 38,358; pascal: 25,559; sh: 20,429; ml: 5,058; perl: 4,745; makefile: 4,484; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (157 lines) | stat: -rw-r--r-- 7,662 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Logging API open source project
//
// Copyright (c) 2018-2019 Apple Inc. and the Swift Logging API project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift Logging API project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
@testable import Logging
import XCTest

class LocalLoggerTest: XCTestCase {
    func test1() throws {
        // bootstrap with our test logging impl
        let logging = TestLogging()
        LoggingSystem.bootstrapInternal(logging.make)

        // change test logging config to log traces and above
        logging.config.set(value: Logger.Level.debug)
        // run our program
        let context = Context()
        Struct1().doSomething(context: context)
        // test results
        logging.history.assertExist(level: .debug, message: "Struct1::doSomething", source: "LoggingTests")
        logging.history.assertNotExist(level: .debug, message: "Struct1::doSomethingElse")
        logging.history.assertExist(level: .info, message: "Struct2::doSomething")
        logging.history.assertExist(level: .info, message: "Struct2::doSomethingElse")
        logging.history.assertExist(level: .error, message: "Struct3::doSomething", metadata: ["bar": "baz"])
        logging.history.assertExist(level: .error, message: "Struct3::doSomethingElse", metadata: ["bar": "baz"])
        logging.history.assertExist(level: .warning, message: "Struct3::doSomethingElseAsync", metadata: ["bar": "baz"])
        logging.history.assertExist(level: .info, message: "TestLibrary::doSomething")
        logging.history.assertExist(level: .info, message: "TestLibrary::doSomethingAsync")
        logging.history.assertExist(level: .debug, message: "Struct3::doSomethingElse::Local", metadata: ["bar": "baz", "baz": "qux"])
        logging.history.assertExist(level: .debug, message: "Struct3::doSomethingElse::end", metadata: ["bar": "baz"])
        logging.history.assertExist(level: .debug, message: "Struct3::doSomething::end", metadata: ["bar": "baz"])
        logging.history.assertExist(level: .debug, message: "Struct2::doSomethingElse::end")
        logging.history.assertExist(level: .debug, message: "Struct1::doSomethingElse::end")
        logging.history.assertExist(level: .debug, message: "Struct1::doSomething::end")
    }

    func test2() throws {
        // bootstrap with our test logging impl
        let logging = TestLogging()
        LoggingSystem.bootstrapInternal(logging.make)

        // change test logging config to log errors and above
        logging.config.set(value: Logger.Level.error)
        // run our program
        let context = Context()
        Struct1().doSomething(context: context)
        // test results
        logging.history.assertNotExist(level: .debug, message: "Struct1::doSomething") // global context
        logging.history.assertNotExist(level: .debug, message: "Struct1::doSomethingElse") // global context
        logging.history.assertExist(level: .info, message: "Struct2::doSomething") // local context
        logging.history.assertExist(level: .info, message: "Struct2::doSomethingElse") // local context
        logging.history.assertExist(level: .error, message: "Struct3::doSomething", metadata: ["bar": "baz"]) // local context
        logging.history.assertExist(level: .error, message: "Struct3::doSomethingElse", metadata: ["bar": "baz"]) // local context
        logging.history.assertExist(level: .warning, message: "Struct3::doSomethingElseAsync", metadata: ["bar": "baz"]) // local context
        logging.history.assertNotExist(level: .info, message: "TestLibrary::doSomething") // global context
        logging.history.assertNotExist(level: .info, message: "TestLibrary::doSomethingAsync") // global context
        logging.history.assertExist(level: .debug, message: "Struct3::doSomethingElse::Local", metadata: ["bar": "baz", "baz": "qux"]) // hyper local context
        logging.history.assertExist(level: .debug, message: "Struct3::doSomethingElse::end", metadata: ["bar": "baz"]) // local context
        logging.history.assertExist(level: .debug, message: "Struct2::doSomethingElse::end") // local context
        logging.history.assertExist(level: .debug, message: "Struct3::doSomething::end", metadata: ["bar": "baz"]) // local context
        logging.history.assertNotExist(level: .debug, message: "Struct1::doSomethingElse::end") // global context
        logging.history.assertNotExist(level: .debug, message: "Struct1::doSomething::end") // global context
    }
}

//  systems that follow the context pattern  need to implement something like this
private struct Context {
    var logger = Logger(label: "LocalLoggerTest::ContextLogger")

    // since logger is a value type, we can reuse our copy to manage logLevel
    var logLevel: Logger.Level {
        get { return self.logger.logLevel }
        set { self.logger.logLevel = newValue }
    }

    // since logger is a value type, we can reuse our copy to manage metadata
    subscript(metadataKey: String) -> Logger.Metadata.Value? {
        get { return self.logger[metadataKey: metadataKey] }
        set { self.logger[metadataKey: metadataKey] = newValue }
    }
}

private struct Struct1 {
    func doSomething(context: Context) {
        context.logger.debug("Struct1::doSomething")
        self.doSomethingElse(context: context)
        context.logger.debug("Struct1::doSomething::end")
    }

    private func doSomethingElse(context: Context) {
        let originalContext = context
        var context = context
        context.logger.logLevel = .warning
        context.logger.debug("Struct1::doSomethingElse")
        Struct2().doSomething(context: context)
        originalContext.logger.debug("Struct1::doSomethingElse::end")
    }
}

private struct Struct2 {
    func doSomething(context: Context) {
        var c = context
        c.logLevel = .info // only effects from this point on
        c.logger.info("Struct2::doSomething")
        self.doSomethingElse(context: c)
        c.logger.debug("Struct2::doSomething::end")
    }

    private func doSomethingElse(context: Context) {
        var c = context
        c.logLevel = .debug // only effects from this point on
        c.logger.info("Struct2::doSomethingElse")
        Struct3().doSomething(context: c)
        c.logger.debug("Struct2::doSomethingElse::end")
    }
}

private struct Struct3 {
    private let queue = DispatchQueue(label: "LocalLoggerTest::Struct3")

    func doSomething(context: Context) {
        var c = context
        c["bar"] = "baz" // only effects from this point on
        c.logger.error("Struct3::doSomething")
        self.doSomethingElse(context: c)
        c.logger.debug("Struct3::doSomething::end")
    }

    private func doSomethingElse(context: Context) {
        context.logger.error("Struct3::doSomethingElse")
        let group = DispatchGroup()
        group.enter()
        self.queue.async {
            context.logger.warning("Struct3::doSomethingElseAsync")
            let library = TestLibrary()
            library.doSomething()
            library.doSomethingAsync {
                group.leave()
            }
        }
        group.wait()
        // only effects the logger instance
        var l = context.logger
        l[metadataKey: "baz"] = "qux"
        l.debug("Struct3::doSomethingElse::Local")
        context.logger.debug("Struct3::doSomethingElse::end")
    }
}