diff --git a/.github/PULL_REQUEST_TEMPLATE/bug_template.yml b/.github/PULL_REQUEST_TEMPLATE/bug_template.md
similarity index 100%
rename from .github/PULL_REQUEST_TEMPLATE/bug_template.yml
rename to .github/PULL_REQUEST_TEMPLATE/bug_template.md
diff --git a/.github/PULL_REQUEST_TEMPLATE/feature_template.yml b/.github/PULL_REQUEST_TEMPLATE/feature_template.md
similarity index 100%
rename from .github/PULL_REQUEST_TEMPLATE/feature_template.yml
rename to .github/PULL_REQUEST_TEMPLATE/feature_template.md
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d544d32..28d58cd 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,10 +13,6 @@ on:
- "Source/**"
- "Tests/**"
-concurrency:
- group: ci
- cancel-in-progress: true
-
jobs:
SwiftLint:
runs-on: ubuntu-latest
@@ -28,40 +24,176 @@ jobs:
args: --strict
env:
DIFF_BASE: ${{ github.base_ref }}
- Latest:
- name: Test Latest (iOS, macOS, tvOS, watchOS)
- runs-on: macOS-12
+ macOS:
+ name: ${{ matrix.name }}
+ runs-on: ${{ matrix.runsOn }}
+ env:
+ DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
+ timeout-minutes: 20
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - xcode: "Xcode_15.0"
+ runsOn: macos-13
+ name: "macOS 13, Xcode 15.0, Swift 5.9.0"
+ - xcode: "Xcode_14.3.1"
+ runsOn: macos-13
+ name: "macOS 13, Xcode 14.3.1, Swift 5.8.0"
+ steps:
+ - uses: actions/checkout@v3
+ - name: ${{ matrix.name }}
+ run: xcodebuild test -scheme "Log" -destination "platform=macOS" clean -enableCodeCoverage YES -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
+ - name: Upload coverage reports to Codecov
+ uses: codecov/codecov-action@v3.1.0
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ xcode: true
+ xcode_archive_path: test_output/${{ matrix.name }}.xcresult
+ - uses: actions/upload-artifact@v4
+ with:
+ name: ${{ matrix.name }}
+ path: test_output
+
+ iOS:
+ name: ${{ matrix.name }}
+ runs-on: ${{ matrix.runsOn }}
+ env:
+ DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
+ timeout-minutes: 20
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - destination: "OS=17.0.1,name=iPhone 14 Pro"
+ name: "iOS 17.0.1"
+ xcode: "Xcode_15.0"
+ runsOn: macos-13
+ - destination: "OS=16.4,name=iPhone 14 Pro"
+ name: "iOS 16.4"
+ xcode: "Xcode_14.3.1"
+ runsOn: macos-13
+ steps:
+ - uses: actions/checkout@v3
+ - name: ${{ matrix.name }}
+ run: xcodebuild test -scheme "Log" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
+ - uses: actions/upload-artifact@v4
+ with:
+ name: ${{ matrix.name }}
+ path: test_output
+
+ tvOS:
+ name: ${{ matrix.name }}
+ runs-on: ${{ matrix.runsOn }}
+ env:
+ DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
+ timeout-minutes: 20
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - destination: "OS=17.0,name=Apple TV"
+ name: "tvOS 17.0"
+ xcode: "Xcode_15.0"
+ runsOn: macos-13
+ - destination: "OS=16.4,name=Apple TV"
+ name: "tvOS 16.4"
+ xcode: "Xcode_14.3.1"
+ runsOn: macos-13
+ steps:
+ - uses: actions/checkout@v3
+ - name: ${{ matrix.name }}
+ run: xcodebuild test -scheme "Log" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
+ - name: Upload coverage reports to Codecov
+ uses: codecov/codecov-action@v3.1.0
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ xcode: true
+ xcode_archive_path: test_output/${{ matrix.name }}.xcresult
+ - uses: actions/upload-artifact@v4
+ with:
+ name: ${{ matrix.name }}
+ path: test_output
+
+ watchOS:
+ name: ${{ matrix.name }}
+ runs-on: ${{ matrix.runsOn }}
env:
- DEVELOPER_DIR: "/Applications/Xcode_14.1.app/Contents/Developer"
- timeout-minutes: 10
+ DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
+ timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- - destination: "OS=16.1,name=iPhone 14 Pro"
- name: "iOS"
- scheme: "Log"
- sdk: iphonesimulator
- - destination: "OS=16.1,name=Apple TV"
- name: "tvOS"
- scheme: "Log"
- sdk: appletvsimulator
- - destination: "OS=9.1,name=Apple Watch Series 8 (45mm)"
- name: "watchOS"
- scheme: "Log"
- sdk: watchsimulator
- - destination: "platform=macOS"
- name: "macOS"
- scheme: "Log"
- sdk: macosx
+ - destination: "OS=10.0,name=Apple Watch Series 9 (45mm)"
+ name: "watchOS 10.0"
+ xcode: "Xcode_15.0"
+ runsOn: macos-13
+ - destination: "OS=9.4,name=Apple Watch Series 8 (45mm)"
+ name: "watchOS 9.4"
+ xcode: "Xcode_14.3.1"
+ runsOn: macos-13
steps:
- uses: actions/checkout@v3
- name: ${{ matrix.name }}
- run: xcodebuild test -scheme "${{ matrix.scheme }}" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "./${{ matrix.sdk }}.xcresult" | xcpretty -r junit
+ run: xcodebuild test -scheme "Log" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3.1.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
xcode: true
- xcode_archive_path: "./${{ matrix.sdk }}.xcresult"
-
\ No newline at end of file
+ xcode_archive_path: test_output/${{ matrix.name }}.xcresult
+ - uses: actions/upload-artifact@v4
+ with:
+ name: ${{ matrix.name }}
+ path: test_output
+
+ spm:
+ name: ${{ matrix.name }}
+ runs-on: ${{ matrix.runsOn }}
+ env:
+ DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
+ timeout-minutes: 20
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - name: "Xcode 15"
+ xcode: "Xcode_15.0"
+ runsOn: macos-13
+ - name: "Xcode 14"
+ xcode: "Xcode_14.3.1"
+ runsOn: macos-13
+ steps:
+ - uses: actions/checkout@v3
+ - name: ${{ matrix.name }}
+ run: swift build -c release
+
+ merge-test-reports:
+ needs: [iOS, macOS, watchOS, tvOS]
+ runs-on: macos-13
+ steps:
+ - name: Download artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: test_output
+ - run: xcrun xcresulttool merge test_output/**/*.xcresult --output-path test_output/final/final.xcresult
+ - name: Upload Merged Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: MergedResult
+ path: test_output/final
+
+ discover-typos:
+ name: Discover Typos
+ runs-on: macOS-12
+ env:
+ DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
+ steps:
+ - uses: actions/checkout@v2
+ - name: Discover typos
+ run: |
+ export PATH="$PATH:/Library/Frameworks/Python.framework/Versions/3.11/bin"
+ python3 -m pip install --upgrade pip
+ python3 -m pip install codespell
+ codespell --ignore-words-list="hart,inout,msdos,sur" --skip="./.build/*,./.git/*"
\ No newline at end of file
diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml
index 1a0ab52..158ca87 100644
--- a/.github/workflows/danger.yml
+++ b/.github/workflows/danger.yml
@@ -15,7 +15,7 @@ jobs:
- name: ruby setup
uses: ruby/setup-ruby@v1
with:
- ruby-version: 2.7
+ ruby-version: 3.1.4
bundler-cache: true
- name: Checkout code
uses: actions/checkout@v2
diff --git a/.swiftlint.yml b/.swiftlint.yml
index 6d90edc..58036d3 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -16,7 +16,6 @@ opt_in_rules: # some rules are only opt-in
- attributes
- closure_body_length
- closure_end_indentation
- - closure_spacing
- collection_alignment
- contains_over_filter_count
- contains_over_filter_is_empty
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 259b66b..aa07494 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,20 @@
All notable changes to this project will be documented in this file.
#### 1.x Releases
+- `1.1.x` Releases - [1.1.0](#110)
- `1.0.x` Releases - [1.0.0](#100)
+## [1.1.0](https://github.com/space-code/log/releases/tag/1.1.0)
+#### Added
+- Make the `logLevel` property changeable
+ - Added in Pull Request [#5](https://github.com/space-code/log/pull/5).
+- Add files to comply with community standards
+ - Added in Pull Request [#4](https://github.com/space-code/log/pull/4).
+- Update GitHub Actions workflow
+ - Added in Pull Request [#3](https://github.com/space-code/log/pull/3).
+- Hide `IOSWriter` & `IConsoleWriter` from the public interface
+ - Added in Pull Request [#2](https://github.com/space-code/log/pull/2).
+
## [1.0.0](https://github.com/space-code/log/releases/tag/1.0.0)
Released on 2023-10-18.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..56c1661
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,74 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting one of the project maintainers https://github.com/orgs/space-code/people. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..349d9ec
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,61 @@
+# Contributing Guidelines
+
+This document contains information and guidelines about contributing to this project.
+Please read it before you start participating.
+
+**Topics**
+
+* [Reporting Issues](#reporting-issues)
+* [Submitting Pull Requests](#submitting-pull-requests)
+* [Developers Certificate of Origin](#developers-certificate-of-origin)
+* [Code of Conduct](#code-of-conduct)
+
+## Reporting Issues
+
+A great way to contribute to the project is to send a detailed issue when you encounter a problem. We always appreciate a well-written, thorough bug report.
+
+Check that the project issues database doesn't already include that problem or suggestion before submitting an issue. If you find a match, feel free to vote for the issue by adding a reaction. Doing this helps prioritize the most common problems and requests.
+
+When reporting issues, please fill out our issue template. The information the template asks for will help us review and fix your issue faster.
+
+## Submitting Pull Requests
+
+You can contribute by fixing bugs or adding new features. For larger code changes, we recommend first discussing your ideas on our [GitHub Discussions](https://github.com/space-code/log/discussions). When submitting a pull request, please add relevant tests and ensure your changes don't break any existing tests.
+
+## Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+- (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+- (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+- (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+- (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+## Code of Conduct
+
+The Code of Conduct governs how we behave in public or in private
+whenever the project will be judged by our actions.
+We expect it to be honored by everyone who contributes to this project.
+
+See [CODE_OF_CONDUCT.md](https://github.com/space-code/log/blob/master/CODE_OF_CONDUCT.md) for details.
+
+---
+
+*Some of the ideas and wording for the statements above were based on work by the [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) and [Linux](https://elinux.org/Developer_Certificate_Of_Origin) communities.
\ No newline at end of file
diff --git a/Package@swift-5.8.swift b/Package@swift-5.8.swift
new file mode 100644
index 0000000..6de492d
--- /dev/null
+++ b/Package@swift-5.8.swift
@@ -0,0 +1,24 @@
+// swift-tools-version: 5.8
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+// swiftlint:disable all
+
+import PackageDescription
+
+let package = Package(
+ name: "Log",
+ platforms: [
+ .macOS(.v10_15),
+ .iOS(.v13),
+ .watchOS(.v7),
+ .tvOS(.v13),
+ ],
+ products: [
+ .library(name: "Log", targets: ["Log"]),
+ ],
+ dependencies: [],
+ targets: [
+ .target(name: "Log", dependencies: []),
+ .testTarget(name: "LogTests", dependencies: ["Log"]),
+ ]
+)
+// swiftlint:enable all
diff --git a/README.md b/README.md
index 03b197d..d3d5638 100644
--- a/README.md
+++ b/README.md
@@ -4,11 +4,13 @@
-
-
+
+
+
+
## Description
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..20dffca
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,7 @@
+# Reporting Security Vulnerabilities
+
+This software is built with security and data privacy in mind to ensure your data is safe. We are grateful for security researchers and users reporting a vulnerability to us, first. To ensure that your request is handled in a timely manner and non-disclosure of vulnerabilities can be assured, please follow the below guideline.
+
+**Please do not report security vulnerabilities directly on GitHub. GitHub Issues can be publicly seen and therefore would result in a direct disclosure.**
+
+* Please address questions about data privacy, security concepts, and other media requests to the nv3212@gmail.com mailbox.
\ No newline at end of file
diff --git a/Sources/Log/Classes/Core/Logger/Logger.swift b/Sources/Log/Classes/Core/Logger/Logger.swift
index 8405788..2af975c 100644
--- a/Sources/Log/Classes/Core/Logger/Logger.swift
+++ b/Sources/Log/Classes/Core/Logger/Logger.swift
@@ -1,8 +1,10 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
+import Foundation
+
// MARK: - Logger
/// A class responsible for logging functionality.
@@ -10,7 +12,14 @@ open class Logger {
// MARK: Properties
/// The current log level for this logger.
- let logLevel: LogLevel
+ private var _logLevel: Atomic
+
+ /// The current log level for this logger.
+ public var logLevel: LogLevel {
+ get { _logLevel.value }
+ set { _logLevel.value = newValue }
+ }
+
/// An array of printer strategies to handle the log output.
let printers: [IPrinterStrategy]
@@ -26,7 +35,7 @@ open class Logger {
logLevel: LogLevel
) {
self.printers = printers
- self.logLevel = logLevel
+ _logLevel = Atomic(value: logLevel)
}
// MARK: Private
@@ -41,7 +50,7 @@ open class Logger {
printers.forEach { $0.log(message, logLevel: logLevel) }
}
- /// Checks if the given `LogLevel` is allowed by the reciever.
+ /// Checks if the given `LogLevel` is allowed by the receiver.
///
/// - Parameter logLevel: The log level to check.
private func isLoggerEnabled(for logLevel: LogLevel) -> Bool {
diff --git a/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift b/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift
index 103e162..cb3018d 100644
--- a/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift
+++ b/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift
@@ -1,6 +1,6 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
import Foundation
@@ -15,16 +15,25 @@ public final class ConsolePrinter {
public let formatters: [ILogFormatter]
/// The console writer.
- public let consoleWriter: IConsoleWriter
+ private let consoleWriter: IConsoleWriter
// MARK: Initialization
+ /// Creates a new `ConsolePrinter` instance.
+ ///
+ /// - Parameters:
+ /// - formatters: An array of log formatters for customizing log messages.
+ public init(formatters: [ILogFormatter]) {
+ self.formatters = formatters
+ consoleWriter = ConsoleWriter()
+ }
+
/// Creates a new `ConsolePrinter` instance.
///
/// - Parameters:
/// - formatters: An array of log formatters for customizing log messages.
/// - consoleWriter: The console writer.
- public init(formatters: [ILogFormatter], consoleWriter: IConsoleWriter = ConsoleWriter()) {
+ init(formatters: [ILogFormatter], consoleWriter: IConsoleWriter) {
self.formatters = formatters
self.consoleWriter = consoleWriter
}
diff --git a/Sources/Log/Classes/Core/Printers/OSPrinter.swift b/Sources/Log/Classes/Core/Printers/OSPrinter.swift
index 1964c56..10bcb55 100644
--- a/Sources/Log/Classes/Core/Printers/OSPrinter.swift
+++ b/Sources/Log/Classes/Core/Printers/OSPrinter.swift
@@ -1,6 +1,6 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
import Foundation
@@ -14,15 +14,9 @@ public final class OSPrinter {
/// An array of log formatters used to customize log message output.
public let formatters: [ILogFormatter]
- /// The optional subsystem for categorizing log messages.
- public let subsystem: String
- /// The optional category for categorizing log messages.
- public let category: String
- /// The os writer.
- public let osWriter: IOSWriter
- /// An internal lazy property for initializing the OSLog instance.
- private lazy var osLog: OSLog = .init(subsystem: subsystem, category: category)
+ /// An os writer.
+ private let osWriter: IOSWriter
// MARK: Initialization
@@ -32,15 +26,24 @@ public final class OSPrinter {
/// - subsystem: An optional subsystem for categorizing log messages.
/// - category: An optional category for categorizing log messages.
/// - formatters: An array of log formatters for customizing log messages.
- /// - osWriter: An os writer.
public init(
- subsystem: String = "os_printer",
- category: String = "",
- formatters: [ILogFormatter],
- osWriter: IOSWriter = OSWriter()
+ subsystem: String,
+ category: String,
+ formatters: [ILogFormatter]
) {
- self.subsystem = subsystem
- self.category = category
+ self.formatters = formatters
+ osWriter = OSWriter(
+ subsystem: subsystem,
+ category: category
+ )
+ }
+
+ /// Creates a new `OSPrinter` instance.
+ ///
+ /// - Parameters:
+ /// - formatters: An array of log formatters for customizing log messages.
+ /// - osWriter: An os writer.
+ init(formatters: [ILogFormatter], osWriter: IOSWriter) {
self.formatters = formatters
self.osWriter = osWriter
}
@@ -52,7 +55,7 @@ extension OSPrinter: IStyleLogStrategy {
public func log(_ message: String, logLevel: LogLevel) {
let message = formatMessage(message, logLevel: logLevel)
let type = sysLogPriority(logLevel)
- osWriter.log("%s", log: osLog, type: type, message)
+ osWriter.log(type: type, message)
}
}
diff --git a/Sources/Log/Classes/Helpers/Atomic/Atomic.swift b/Sources/Log/Classes/Helpers/Atomic/Atomic.swift
new file mode 100644
index 0000000..6d0b4cb
--- /dev/null
+++ b/Sources/Log/Classes/Helpers/Atomic/Atomic.swift
@@ -0,0 +1,43 @@
+//
+// log
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import Foundation
+
+// MARK: - Atomic
+
+/// The Atomic class is designed to provide thread-safe access to a mutable value.
+final class Atomic {
+ // MARK: Properties
+
+ /// NSLock instance for synchronization.
+ private let lock = NSLock()
+ /// The actual mutable value.
+ private var _value: Value
+
+ /// Computed property to get and set the value atomically
+ var value: Value {
+ get { lock.synchronized { _value } }
+ set { lock.synchronized { _value = newValue }}
+ }
+
+ // MARK: Initialization
+
+ /// Initializes the Atomic instance with an initial value.
+ init(value: Value) {
+ _value = value
+ }
+}
+
+// MARK: - Extensions
+
+private extension NSLock {
+ /// Synchronizes a code block using the NSLock instance.
+ /// This helps ensure that only one thread can access the critical section at a time.
+ func synchronized(block: () throws -> T) rethrows -> T {
+ lock()
+ defer { unlock() }
+ return try block()
+ }
+}
diff --git a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift
index 1549580..adaf162 100644
--- a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift
+++ b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift
@@ -1,6 +1,6 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
import Foundation
@@ -8,15 +8,15 @@ import Foundation
// MARK: - ConsoleWriter
/// A class that conforms to the IConsoleWriter protocol and writes messages to the console output.
-public final class ConsoleWriter: IConsoleWriter {
+final class ConsoleWriter: IConsoleWriter {
// MARK: Initialization
/// Initializes a new ConsoleWriter instance.
- public init() {}
+ init() {}
// MARK: IConsoleWriter
- public func print(_ message: String) {
+ func print(_ message: String) {
Swift.print(message)
}
}
diff --git a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift
index 09d5a93..b0b5b6c 100644
--- a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift
+++ b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift
@@ -1,12 +1,12 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
import Foundation
/// A protocol for writing messages to the console.
-public protocol IConsoleWriter {
+protocol IConsoleWriter {
/// Prints a message to the console output.
///
/// - Parameter message: The message to be printed as a String.
diff --git a/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift b/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift
index ec2fcab..29aa5f9 100644
--- a/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift
+++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift
@@ -1,6 +1,6 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
import Foundation
@@ -11,9 +11,7 @@ public protocol IOSWriter {
/// Writes a log message to the specified OSLog.
///
/// - Parameters:
- /// - message: A StaticString containing the log message format.
- /// - log: An OSLog object representing the log subsystem and category.
/// - type: An OSLogType indicating the log message type.
- /// - args: A variadic list of CVarArg values to fill in the message format.
- func log(_ message: StaticString, log: OSLog, type: OSLogType, _ args: CVarArg...)
+ /// - message: A variadic list of String values to fill in the message format.
+ func log(type: OSLogType, _ message: String)
}
diff --git a/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift b/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift
index a4ad3ad..8af506b 100644
--- a/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift
+++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift
@@ -1,6 +1,6 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
import Foundation
@@ -8,16 +8,63 @@ import OSLog
// MARK: - OSWriter
-/// A class that conforms to the IOSWriter protocol and writes log messages to the Apple OSLog system.
-public final class OSWriter: IOSWriter {
+final class OSWriter: IOSWriter {
+ // MARK: Properties
+
+ /// The optional subsystem for categorizing log messages.
+ private let subsystem: String
+ /// The optional category for categorizing log messages.
+ private let category: String
+
+ /// An internal lazy property for initializing the OSLog instance.
+ private var osLog: OSLog { OSLog(subsystem: subsystem, category: category) }
+
+ /// An internal lazy property for initializing WriteStrategy instance.
+ private lazy var writerStrategy: IOSWriterStrategy = {
+ if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
+ return os.Logger(osLog)
+ } else {
+ return LegacyOSLogger(osLog: osLog)
+ }
+ }()
+
// MARK: Initialization
- /// Creates a new `OSWriter` instance.
- public init() {}
+ /// Creates a `OSWriter` instance.
+ ///
+ /// - Parameters:
+ /// - subsystem: An optional subsystem for categorizing log messages.
+ /// - category: An optional category for categorizing log messages.
+ init(subsystem: String, category: String) {
+ self.subsystem = subsystem
+ self.category = category
+ }
// MARK: IOSWriter
- public func log(_ message: StaticString, log: OSLog, type: OSLogType, _ args: CVarArg...) {
- os_log(message, log: log, type: type, args)
+ func log(type: OSLogType, _ message: String) {
+ writerStrategy.log(type: type, message)
+ }
+}
+
+// MARK: OSWriter.LegacyOSLogger
+
+private extension OSWriter {
+ struct LegacyOSLogger: IOSWriterStrategy {
+ // MARK: Private
+
+ private let osLog: OSLog
+
+ // MARK: Initialization
+
+ init(osLog: OSLog) {
+ self.osLog = osLog
+ }
+
+ // MARK: IOSWriterStrategy
+
+ func log(type: OSLogType, _ message: String) {
+ os_log("%s", log: osLog, type: type, message)
+ }
}
}
diff --git a/Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift b/Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift
new file mode 100644
index 0000000..bb8f3ed
--- /dev/null
+++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift
@@ -0,0 +1,27 @@
+//
+// log
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import os
+
+// MARK: - IOSWriterStrategy
+
+/// Protocol defining the contract for a logger strategy that writes logs to the iOS system logs using OSLog.
+protocol IOSWriterStrategy {
+ /// Writes a log message to the iOS system logs with the specified log type.
+ ///
+ /// - Parameters:
+ /// - type: The type of the log message (debug, info, error, etc.).
+ /// - message: The message to be logged.
+ func log(type: OSLogType, _ message: String)
+}
+
+// MARK: - os.Logger + IOSWriterStrategy
+
+@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
+extension os.Logger: IOSWriterStrategy {
+ func log(type: OSLogType, _ message: String) {
+ log(level: type, "\(message)")
+ }
+}
diff --git a/Tests/LogTests/IntegrationTests/LogIntegrationTests.swift b/Tests/LogTests/IntegrationTests/LogIntegrationTests.swift
new file mode 100644
index 0000000..c87b149
--- /dev/null
+++ b/Tests/LogTests/IntegrationTests/LogIntegrationTests.swift
@@ -0,0 +1,70 @@
+//
+// log
+// Copyright © 2024 Space Code. All rights reserved.
+//
+
+import Log
+import XCTest
+
+// MARK: - LogIntegrationTests
+
+final class LogIntegrationTests: XCTestCase {
+ // MARK: Properties
+
+ private var sut: Logger!
+
+ // MARK: XCTestCase
+
+ override func setUp() {
+ super.setUp()
+ let formatters: [ILogFormatter] = [
+ TimestampLogFormatter(dateFormat: "dd/MM/yyyy"),
+ PrefixLogFormatter(name: "LogIntegrationTests"),
+ ]
+
+ sut = Logger(
+ printers: [
+ ConsolePrinter(
+ formatters: formatters
+ ),
+ OSPrinter(
+ subsystem: .subsystem,
+ category: .category,
+ formatters: formatters
+ ),
+ ],
+ logLevel: .all
+ )
+ }
+
+ override func tearDown() {
+ sut = nil
+ super.tearDown()
+ }
+
+ // MARK: Tests
+
+ // The test just checks that the methods don't cause a crash
+ // when printing a message to different outputs.
+ func test_logDoesNotThrowUnexpectedBehavior_whenLogMessages() {
+ // 1. Print an info message
+ sut.info(message: .message)
+
+ // 2. Print a debug message
+ sut.debug(message: .message)
+
+ // 3. Print an error message
+ sut.error(message: .message)
+
+ // 4. Print a fault message
+ sut.fault(message: .message)
+ }
+}
+
+// MARK: - Constants
+
+private extension String {
+ static let subsystem = "subsystem"
+ static let category = "category"
+ static let message = "text"
+}
diff --git a/Tests/LogTests/Mocks/ConsoleWriterMock.swift b/Tests/LogTests/Mocks/ConsoleWriterMock.swift
index 7b0cec8..620f81b 100644
--- a/Tests/LogTests/Mocks/ConsoleWriterMock.swift
+++ b/Tests/LogTests/Mocks/ConsoleWriterMock.swift
@@ -1,10 +1,10 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
import Foundation
-import Log
+@testable import Log
final class ConsoleWriterMock: IConsoleWriter {
var invokedPrint = false
diff --git a/Tests/LogTests/Mocks/OSWriterMock.swift b/Tests/LogTests/Mocks/OSWriterMock.swift
index 165dc09..0d00eb1 100644
--- a/Tests/LogTests/Mocks/OSWriterMock.swift
+++ b/Tests/LogTests/Mocks/OSWriterMock.swift
@@ -1,21 +1,21 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
-import Log
+@testable import Log
import OSLog
final class OSWriterMock: IOSWriter {
var invokedLog = false
var invokedLogCount = 0
- var invokedLogParameters: (message: StaticString, log: OSLog, type: OSLogType, args: CVarArg)?
- var invokedLogParametersList = [(message: StaticString, log: OSLog, type: OSLogType, args: CVarArg)]()
+ var invokedLogParameters: (type: OSLogType, message: String)?
+ var invokedLogParametersList = [(type: OSLogType, message: String)]()
- func log(_ message: StaticString, log: OSLog, type: OSLogType, _ args: CVarArg...) {
+ func log(type: OSLogType, _ message: String) {
invokedLog = true
invokedLogCount += 1
- invokedLogParameters = (message, log, type, args)
- invokedLogParametersList.append((message, log, type, args))
+ invokedLogParameters = (type, message)
+ invokedLogParametersList.append((type, message))
}
}
diff --git a/Tests/LogTests/UnitTests/ConsolePrinterTests.swift b/Tests/LogTests/UnitTests/ConsolePrinterTests.swift
index 4478dfd..c14640a 100644
--- a/Tests/LogTests/UnitTests/ConsolePrinterTests.swift
+++ b/Tests/LogTests/UnitTests/ConsolePrinterTests.swift
@@ -1,9 +1,9 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
-import Log
+@testable import Log
import XCTest
// MARK: - ConsolePrinterTests
diff --git a/Tests/LogTests/UnitTests/LogTests.swift b/Tests/LogTests/UnitTests/LogTests.swift
index 4284ac4..a9bf700 100644
--- a/Tests/LogTests/UnitTests/LogTests.swift
+++ b/Tests/LogTests/UnitTests/LogTests.swift
@@ -1,6 +1,6 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
import Log
@@ -119,6 +119,21 @@ final class LogTests: XCTestCase {
XCTAssertNil(printerMock.invokedLogParameters?.message)
}
+ func test_thatLoggerDoesNotPrintAnything_whenLogLevelValueDidChange() {
+ // given
+ let sut = prepareSut()
+
+ // when
+ sut.logLevel = .info
+ sut.debug(message: .message)
+ sut.info(message: .message)
+
+ // then
+ XCTAssertEqual(sut.logLevel, .info)
+ XCTAssertEqual(printerMock.invokedLogCount, 1)
+ XCTAssertEqual(printerMock.invokedLogParameters?.message, .message)
+ }
+
// MARK: Private
private func prepareSut(logLevel: LogLevel = .all) -> Logger {
diff --git a/Tests/LogTests/UnitTests/OSPrinterTests.swift b/Tests/LogTests/UnitTests/OSPrinterTests.swift
index f4175a5..d3a69fd 100644
--- a/Tests/LogTests/UnitTests/OSPrinterTests.swift
+++ b/Tests/LogTests/UnitTests/OSPrinterTests.swift
@@ -1,9 +1,9 @@
//
// log
-// Copyright © 2023 Space Code. All rights reserved.
+// Copyright © 2024 Space Code. All rights reserved.
//
-import Log
+@testable import Log
import XCTest
// MARK: - OSPrinterTests
@@ -23,8 +23,6 @@ final class OSPrinterTests: XCTestCase {
formatterMock = LogFormatterMock()
osWriterMock = OSWriterMock()
sut = OSPrinter(
- subsystem: .subsystem,
- category: .category,
formatters: [formatterMock],
osWriter: osWriterMock
)
@@ -47,7 +45,7 @@ final class OSPrinterTests: XCTestCase {
sut.log(.message, logLevel: .all)
// then
- XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message)
+ XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message)
}
func test_thatConsolePrinterLogsMessage_whenLogLevelIsDebug() {
@@ -58,7 +56,7 @@ final class OSPrinterTests: XCTestCase {
sut.log(.message, logLevel: .debug)
// then
- XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message)
+ XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message)
}
func test_thatConsolePrinterLogsMessage_whenLogLevelIsInfo() {
@@ -69,7 +67,7 @@ final class OSPrinterTests: XCTestCase {
sut.log(.message, logLevel: .info)
// then
- XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message)
+ XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message)
}
func test_thatConsolePrinterLogsMessage_whenLogLevelIsError() {
@@ -80,7 +78,7 @@ final class OSPrinterTests: XCTestCase {
sut.log(.message, logLevel: .error)
// then
- XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message)
+ XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message)
}
func test_thatConsolePrinterLogsMessage_whenLogLevelIsFault() {
@@ -91,7 +89,7 @@ final class OSPrinterTests: XCTestCase {
sut.log(.message, logLevel: .fault)
// then
- XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message)
+ XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message)
}
}
diff --git a/codecov.yml b/codecov.yml
index b415604..8bb858a 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -32,7 +32,7 @@ coverage:
target: 85%
# Allow coverage to drop by X%
- threshold: 5%
+ threshold: 50%
changes: no
comment: