Allow setting custom log levels (#1592)

* Allow using custom tracing configuration from the developer options screen. Clean up RustTracing
* Move log level configurations to a separate view
* Disable autocorrection
* Fix unit tests
* Use TracingConfiguration.info as the default text value, switch to a TextEditor
This commit is contained in:
Stefan Ceriu
2023-08-30 15:35:49 +03:00
committed by GitHub
parent 1eaf731f3b
commit 161c549ffd
4 changed files with 109 additions and 44 deletions

View File

@@ -59,7 +59,7 @@ enum MXLog {
return
}
setupTracing(configuration: .custom(logLevel: logLevel), otlpConfiguration: otlpConfiguration)
setupTracing(configuration: .init(logLevel: logLevel), otlpConfiguration: otlpConfiguration)
if let target {
self.target = target

View File

@@ -27,31 +27,45 @@ struct OTLPConfiguration {
// We can filter by level, crate and even file. See more details here:
// https://docs.rs/tracing-subscriber/0.2.7/tracing_subscriber/filter/struct.EnvFilter.html#examples
struct TracingConfiguration {
/// Configure tracing with certain overrides in place
/// - Parameter overrides: the desired overrides
/// - Returns: a custom tracing configuration
static func custom(overrides: [Target: LogLevel]) -> TracingConfiguration {
TracingConfiguration(overrides: overrides)
}
/// Sets the same log level for all Targets
/// - Parameter logLevel: the desired log level
/// - Returns: a custom tracing configuration
static func custom(logLevel: LogLevel) -> TracingConfiguration {
let overrides = targets.keys.reduce(into: [Target: LogLevel]()) { partialResult, target in
// Keep the defaults here
if target == .common || target == .hyper {
return
enum LogLevel: Codable, Hashable {
case error, warn, info, debug, trace
case custom(String)
var title: String {
switch self {
case .error:
return "Error"
case .warn:
return "Warning"
case .info:
return "Info"
case .debug:
return "Debug"
case .trace:
return "Trace"
case .custom:
return "Custom"
}
}
fileprivate var rawValue: String {
switch self {
case .error:
return "error"
case .warn:
return "warn"
case .info:
return "info"
case .debug:
return "debug"
case .trace:
return "trace"
case .custom(let filter):
return filter
}
partialResult[target] = logLevel
}
return TracingConfiguration(overrides: overrides)
}
enum LogLevel: String, Codable, CaseIterable { case error, warn, info, debug, trace }
enum Target: String {
case common = ""
@@ -77,9 +91,26 @@ struct TracingConfiguration {
.matrix_sdk_ui_timeline: .info
]
var overrides = [Target: LogLevel]()
let filter: String
var filter: String {
/// Sets the same log level for all Targets
/// - Parameter logLevel: the desired log level
/// - Returns: a custom tracing configuration
init(logLevel: LogLevel) {
if case let .custom(filter) = logLevel {
self.filter = filter
return
}
let overrides = Self.targets.keys.reduce(into: [Target: LogLevel]()) { partialResult, target in
// Keep the defaults here
if target == .common || target == .hyper {
return
}
partialResult[target] = logLevel
}
var newTargets = Self.targets
for (target, logLevel) in overrides {
newTargets.updateValue(logLevel, forKey: target)
@@ -93,7 +124,7 @@ struct TracingConfiguration {
return "\(target.rawValue)=\(logLevel.rawValue)"
}
return components.joined(separator: ",")
filter = components.joined(separator: ",")
}
}

View File

@@ -19,18 +19,11 @@ import SwiftUI
struct DeveloperOptionsScreen: View {
@ObservedObject var context: DeveloperOptionsScreenViewModel.Context
@State private var showConfetti = false
var body: some View {
Form {
Section("Logging") {
Picker(selection: $context.logLevel) {
ForEach(TracingConfiguration.LogLevel.allCases, id: \.self) { logLevel in
Text(logLevel.rawValue.capitalized)
}
} label: {
Text("Log level")
Text("Requires app reboot")
}
LogLevelConfigurationView(logLevel: $context.logLevel)
Toggle(isOn: $context.otlpTracingEnabled) {
Text("OTLP tracing")
@@ -130,6 +123,51 @@ struct DeveloperOptionsScreen: View {
}
}
private struct LogLevelConfigurationView: View {
@Binding var logLevel: TracingConfiguration.LogLevel
@State private var customTracingConfiguration: String
init(logLevel: Binding<TracingConfiguration.LogLevel>) {
_logLevel = logLevel
if case .custom(let configuration) = logLevel.wrappedValue {
customTracingConfiguration = configuration
} else {
customTracingConfiguration = TracingConfiguration(logLevel: .info).filter
}
}
var body: some View {
Picker(selection: $logLevel) {
ForEach(logLevels, id: \.self) { logLevel in
Text(logLevel.title)
}
} label: {
Text("Log level")
Text("Requires app reboot")
}
if case .custom = logLevel {
TextEditor(text: $customTracingConfiguration)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
.onChange(of: customTracingConfiguration) { newValue in
logLevel = .custom(newValue)
}
}
}
/// Allows the picker to work with associated values
private var logLevels: [TracingConfiguration.LogLevel] {
if case let .custom(filter) = logLevel {
return [.error, .warn, .info, .debug, .trace, .custom(filter)]
} else {
return [.error, .warn, .info, .debug, .trace, .custom("")]
}
}
}
// MARK: - Previews
struct DeveloperOptionsScreen_Previews: PreviewProvider {

View File

@@ -20,17 +20,13 @@ import XCTest
class TracingConfigurationTests: XCTestCase {
func testConfiguration() {
let configuration = TracingConfiguration(overrides: [.common: .trace,
.matrix_sdk_base_sliding_sync: .error,
.matrix_sdk_http_client: .warn,
.matrix_sdk_crypto: .info,
.hyper: .debug])
let configuration = TracingConfiguration(logLevel: .trace)
let filterComponents = configuration.filter.components(separatedBy: ",")
XCTAssertEqual(filterComponents.first, "trace")
XCTAssertTrue(filterComponents.contains("matrix_sdk_base::sliding_sync=error"))
XCTAssertTrue(filterComponents.contains("matrix_sdk::http_client=warn"))
XCTAssertTrue(filterComponents.contains("matrix_sdk_crypto=info"))
XCTAssertTrue(filterComponents.contains("hyper=debug"))
XCTAssertEqual(filterComponents.first, "info")
XCTAssertTrue(filterComponents.contains("matrix_sdk_base::sliding_sync=trace"))
XCTAssertTrue(filterComponents.contains("matrix_sdk::http_client=trace"))
XCTAssertTrue(filterComponents.contains("matrix_sdk_crypto=trace"))
XCTAssertTrue(filterComponents.contains("hyper=warn"))
}
}