Spy is a flexible, lightweight, multiplatform logging utility written in pure Swift.

Overview

Build Status codecov Carthage compatible Cocoapods Platform Platform License

Spy is a flexible, lightweight, multiplatform logging utility written in pure Swift. It allows to log on different levels and channels which you can define on your own depending on your needs.

Requirements

Development

Project uses following tools for development

  1. XCodeGen
  2. Cocoapods
  3. SwiftLint
  4. Sourcery

Installation

To get started with the Spy you first have to decide how you will integrate it with your project. Spy supports following tools:

Cocoapods

To install Spy using Cocoapods go through following steps:

  1. Add the following entry in your Podfile:
pod 'Spy'
  1. Then run pod install.

Carthage

To install Spy using Carthage go through following steps:

  1. Add the following entry to your Cartfile
github "appunite/Spy"
  1. Then run carthage update

Swift Package Manager

To install Spy using Swift Package Manager go through following steps:

  1. Add following package dependency in you Package.swift .package(url: "https://github.com/appunite/Spy.git", from: "0.5.0")
  2. Add following target dependency in your Package.swift dependencies: ["Spy"])

For instance this is how it might look like:

import PackageDescription

let package = Package(
    name: "YourLibrary",
    products: [
        .library(
            name: "YourLibrary",
            targets: ["YourLibrary"])
    ],
    dependencies: [
        .package(url: "https://github.com/appunite/Spy.git", from: "0.5.0")
    ],
    targets: [
        .target(
            name: "YourLibrary",
            dependencies: ["Spy"])
    ]
)

Overview

Here is a quick overview of functionalities and concepts used in Spy.

SpyChannel

SpyChannel is anything that implements PSpyChannel protocol. Channels can be used to categorize logs. Typically they are implemented with an enum. You can define your own channels as follows:

public enum SpyChannel: String, PSpyChannel {
    case foo
    case bar
    
    public var channelName: String {
        return self.rawValue
    }
}

SpyLevel

SpyLevel is anything that implements PSpyLevel protocol. You can define your own levels, but Spy commes with one set defined for you so you can use it if you want. This set is called SpyLevel and contains following alert levels: finest, finer, fine, config, info, warning, severe sorted by the increasing alert priority.

SpyConfiguration

Contains levels and channels that the Spy will spy on.

SpyConfigurationBuilder

Builds your spy configuration by providing add and remove functions for both levels and channels. Example usage:

SpyConfigurationBuilder()
    .add(level: .severe)
    .add(channels: [.foo, .bar])
    .build()

Spyable

Spyable is a entity that can be logged. It has to implement PSpyable protocol. You can define your own spyables or use string as a basic one.

Spied

Spied is a property wrapper that allows to log all changes and accesses to a property. Example usage:

class Foo {
    @Spied(spy: Environment.spy, onLevel: .info, onChannel: .foo) var foo = "foo"
}

Spy

Spy is anything that implements PSpy protocol. There are a few spies already defined for you:

  • ConsoleSpy - spy that logs spyables by using print command
  • FileSpy - spy that logs spyables into the filesystem (allows to create monolith or chunked logs)
  • CompositeSpy - spy that groups multiple spies into one
  • AnySpy - type-erased spy - every spy can be converted to AnySpy

Logging is performed with log method as follows:

spy.log(level: .severe, channel: .foo, message: "Something bad happened")

ConsoleSpy

ConsoleSpy comes with two available output formatters RawSpyFormatter and DecoratedSpyFormatter with the later being extendable with decorators. You can always define your own output formatter. Example output for RawSpyFormatter will look like:

info::foo::Hello Spy

And example output for DecoratedSpyFormatter may look like:

ℹ️ info::foo::Hello Spy

Log example

Example

This is an example definition of the spies. It utilizes CompositeSpy to allow you to log onto multiple destinations (Console and File).

public static var spy: AnySpy 
   = {
    
   return 
   CompositeSpy()
        .
   add(
   spy: ConsoleSpy
   <SpyLevel, SpyChannel, DecoratedSpyFormatter
   >(
            
   spyFormatter: 
   DecoratedSpyFormatter(
                
   levelNameBuilder: DecoratedLevelNameBuilder
   <SpyLevel
   >()
                    .
   add(
   decorator: 
   EmojiPrefixedSpyLevelNameDecorator().
   any())
                    ),
            
   timestampProvider: 
   CurrentTimestampProvider(),
            
   configuration: 
   SpyConfigurationBuilder()
                .
   add(
   levels: SpyLevel.
   levelsFrom(loggingLevel))
                .
   add(
   channel: .
   foo)
            .
   build()).
   any())
        .
   add(
   spy: FileSpy
   <SpyLevel, SpyChannel, DecoratedSpyFormatter
   >(
            
   logFile: 
   LogFile(
                
   type: .
   chunked(
   maxLogsPerFile: 
   3),
                
   directoryURL: logDirectoryURL),
            
   spyFormatter: 
   DecoratedSpyFormatter(
                
   levelNameBuilder: DecoratedLevelNameBuilder
   <SpyLevel
   >()
                    .
   add(
   decorator: 
   EmojiPrefixedSpyLevelNameDecorator().
   any())
            ),
            
   timestampProvider: 
   CurrentTimestampProvider(),
            
   configuration: 
   SpyConfigurationBuilder()
                .
   add(
   level: .
   severe)
                .
   add(
   channels: [.
   foo, .
   bar])
                .
   build()).
   safe().
   any()
        ).
   any()
}()
  

By using preprocessor we can define different logging levels for debug and release. That way we won't forget about switching off unimportant logs before release.

public extension Environment {
	static var loggingLevel: SpyLevel {
        #if DEBUG
        return .info
        #else
        return .warning
        #endif
    }
}

And here is how you could use Spy:

Environment.spy.log(level: .info, channel: .foo, message: "Hello Spy")

For more detailed example please see the source code.

Contribution

Project is created and maintained by Tomasz Lewandowski.

If you created some new feature or fixed a bug you can create a pull request. Please feel free to submit your feature requests if you have any.

License

Spy is released under an MIT license. See License.md for more information.

You might also like...
CleanroomLogger provides an extensible Swift-based logging API that is simple, lightweight and performant
CleanroomLogger provides an extensible Swift-based logging API that is simple, lightweight and performant

CleanroomLogger CleanroomLogger provides an extensible Swift-based logging API that is simple, lightweight and performant. The API provided by Cleanro

A lightweight logging framework for Swift

HeliumLogger Provides a lightweight logging implementation for Swift which logs to standard output. Features Logs output to stdout by default. You can

A lightweight logging framework for Swift

HeliumLogger Provides a lightweight logging implementation for Swift which logs to standard output. Features Logs output to stdout by default. You can

Convenient & secure logging during development & release in Swift 3, 4 & 5
Convenient & secure logging during development & release in Swift 3, 4 & 5

Colorful, flexible, lightweight logging for Swift 3, Swift 4 & Swift 5. Great for development & release with support for Console, File & cloud platfor

An extensible logging framework for Swift
An extensible logging framework for Swift

Log is a powerful logging framework that provides built-in themes and formatters, and a nice API to define your owns. Get the most out of Log by insta

A powerful input-agnostic swift logging framework made to speed up development with maximum readability.
A powerful input-agnostic swift logging framework made to speed up development with maximum readability.

The Swift logging framework. Atlantis is an extremely powerful logging framework that I've created for everyday use, including enterprise development

Most natural Swift logging

Evergreen Most natural Swift logging Evergreen is a logging framework written in Swift. It is designed to work just as you would expect, yet so versat

A simple logging package for Swift

OhMyLog OhMyLog is a simple logging package for Swift. It supports the following features: Six logging levels ( 👣 , 🔍 , 💡 , ⚠️ , 🚨 , 💊 ) Display

Simple logging for simples needs.

Simple logging for simples needs.

Comments
  • Bump tzinfo from 1.2.5 to 1.2.10

    Bump tzinfo from 1.2.5 to 1.2.10

    Bumps tzinfo from 1.2.5 to 1.2.10.

    Release notes

    Sourced from tzinfo's releases.

    v1.2.10

    TZInfo v1.2.10 on RubyGems.org

    v1.2.9

    • Fixed an incorrect InvalidTimezoneIdentifier exception raised when loading a zoneinfo file that includes rules specifying an additional transition to the final defined offset (for example, Africa/Casablanca in version 2018e of the Time Zone Database). #123.

    TZInfo v1.2.9 on RubyGems.org

    v1.2.8

    • Added support for handling "slim" format zoneinfo files that are produced by default by zic version 2020b and later. The POSIX-style TZ string is now used calculate DST transition times after the final defined transition in the file. The 64-bit section is now always used regardless of whether Time has support for 64-bit times. #120.
    • Rubinius is no longer supported.

    TZInfo v1.2.8 on RubyGems.org

    v1.2.7

    • Fixed 'wrong number of arguments' errors when running on JRuby 9.0. #114.
    • Fixed warnings when running on Ruby 2.8. #112.

    TZInfo v1.2.7 on RubyGems.org

    v1.2.6

    • Timezone#strftime('%s', time) will now return the correct number of seconds since the epoch. #91.
    • Removed the unused TZInfo::RubyDataSource::REQUIRE_PATH constant.
    • Fixed "SecurityError: Insecure operation - require" exceptions when loading data with recent Ruby releases in safe mode.
    • Fixed warnings when running on Ruby 2.7. #106 and #111.

    TZInfo v1.2.6 on RubyGems.org

    Changelog

    Sourced from tzinfo's changelog.

    Version 1.2.10 - 19-Jul-2022

    Version 1.2.9 - 16-Dec-2020

    • Fixed an incorrect InvalidTimezoneIdentifier exception raised when loading a zoneinfo file that includes rules specifying an additional transition to the final defined offset (for example, Africa/Casablanca in version 2018e of the Time Zone Database). #123.

    Version 1.2.8 - 8-Nov-2020

    • Added support for handling "slim" format zoneinfo files that are produced by default by zic version 2020b and later. The POSIX-style TZ string is now used calculate DST transition times after the final defined transition in the file. The 64-bit section is now always used regardless of whether Time has support for 64-bit times. #120.
    • Rubinius is no longer supported.

    Version 1.2.7 - 2-Apr-2020

    • Fixed 'wrong number of arguments' errors when running on JRuby 9.0. #114.
    • Fixed warnings when running on Ruby 2.8. #112.

    Version 1.2.6 - 24-Dec-2019

    • Timezone#strftime('%s', time) will now return the correct number of seconds since the epoch. #91.
    • Removed the unused TZInfo::RubyDataSource::REQUIRE_PATH constant.
    • Fixed "SecurityError: Insecure operation - require" exceptions when loading data with recent Ruby releases in safe mode.
    • Fixed warnings when running on Ruby 2.7. #106 and #111.
    Commits
    • 0814dcd Fix the release date.
    • fd05e2a Preparing v1.2.10.
    • b98c32e Merge branch 'fix-directory-traversal-1.2' into 1.2
    • ac3ee68 Remove unnecessary escaping of + within regex character classes.
    • 9d49bf9 Fix relative path loading tests.
    • 394c381 Remove private_constant for consistency and compatibility.
    • 5e9f990 Exclude Arch Linux's SECURITY file from the time zone index.
    • 17fc9e1 Workaround for 'Permission denied - NUL' errors with JRuby on Windows.
    • 6bd7a51 Update copyright years.
    • 9905ca9 Fix directory traversal in Timezone.get when using Ruby data source
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump cocoapods-downloader from 1.2.2 to 1.6.3

    Bump cocoapods-downloader from 1.2.2 to 1.6.3

    Bumps cocoapods-downloader from 1.2.2 to 1.6.3.

    Release notes

    Sourced from cocoapods-downloader's releases.

    1.6.3

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.2

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.1

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.0

    Enhancements
    • None.
    Bug Fixes
    • Adds a check for command injections in the input for hg and git.
      orta #124

    1.5.1

    Enhancements
    • None.
    Bug Fixes
    • Fix "can't modify frozen string" errors when pods are integrated using the branch option
      buju77 #10920

    1.5.0

    ... (truncated)

    Changelog

    Sourced from cocoapods-downloader's changelog.

    1.6.3 (2022-04-01)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.2 (2022-03-28)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.1 (2022-03-23)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.0 (2022-03-22)

    Enhancements
    • None.
    Bug Fixes
    • Adds a check for command injections in the input for hg and git.
      orta #124

    1.5.1 (2021-09-07)

    Enhancements
    • None.

    ... (truncated)

    Commits
    • c03e2ed Release 1.6.3
    • f75bccc Disable Bazaar tests due to macOS 12.3 not including python2
    • 52a0d54 Merge pull request #128 from CocoaPods/validate_before_dl
    • d27c983 Ensure that the git pre-processor doesn't accidentally bail also
    • 3adfe1f [CHANGELOG] Add empty Master section
    • 591167a Release 1.6.2
    • d2564c3 Merge pull request #127 from CocoaPods/validate_before_dl
    • 99fec61 Switches where we check for invalid input, to move it inside the download fun...
    • 96679f2 [CHANGELOG] Add empty Master section
    • 3a7c54b Release 1.6.1
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump json from 2.2.0 to 2.3.1

    Bump json from 2.2.0 to 2.3.1

    Bumps json from 2.2.0 to 2.3.1.

    Changelog

    Sourced from json's changelog.

    2020-06-30 (2.3.1)

    • Spelling and grammar fixes for comments. Pull request #191 by Josh Kline.
    • Enhance generic JSON and #generate docs. Pull request #347 by Victor Shepelev.
    • Add :nodoc: for GeneratorMethods. Pull request #349 by Victor Shepelev.
    • Baseline changes to help (JRuby) development. Pull request #371 by Karol Bucek.
    • Add metadata for rubygems.org. Pull request #379 by Alexandre ZANNI.
    • Remove invalid JSON.generate description from JSON module rdoc. Pull request #384 by Jeremy Evans.
    • Test with TruffleRuby in CI. Pull request #402 by Benoit Daloze.
    • Rdoc enhancements. Pull request #413 by Burdette Lamar.
    • Fixtures/ are not being tested... Pull request #416 by Marc-André Lafortune.
    • Use frozen string for hash key. Pull request #420 by Marc-André Lafortune.
    • Added :call-seq: to RDoc for some methods. Pull request #422 by Burdette Lamar.
    • Small typo fix. Pull request #423 by Marc-André Lafortune.

    2019-12-11 (2.3.0)

    • Fix default of create_additions to always be false for JSON(user_input) and JSON.parse(user_input, nil). Note that JSON.load remains with default true and is meant for internal serialization of trusted data. [CVE-2020-10663]
    • Fix passing args all #to_json in json/add/*.
    • Fix encoding issues
    • Fix issues of keyword vs positional parameter
    • Fix JSON::Parser against bigdecimal updates
    • Bug fixes to JRuby port
    Commits
    • 0951d77 Bump version to 2.3.1
    • ddc29e2 Merge pull request #429 from flori/remove-generate-task-for-gemspec
    • cee8020 Removed gemspec task from default task on Rakefile
    • 9fd6371 Use VERSION file instead of hard-coded value
    • dc90bcf Removed explicitly date field in gemspec, it will assign by rubygems.org
    • 4c11a40 Removed task for json_pure.gemspec
    • e794ec9 Merge pull request #426 from marcandre/indent
    • 7cc9301 Merge pull request #428 from marcandre/change_fix
    • 9e2a1fb Make changes more precise #424
    • f8fa987 Merge pull request #424 from marcandre/update_changes
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
Releases(0.5.0)
Owner
AppUnite Sp. z o.o. Spk.
AppUnite Sp. z o.o. Spk.
A logging backend for swift-log that sends logging messages to Logstash (eg. the ELK stack)

LoggingELK LoggingELK is a logging backend library for Apple's swift-log The LoggingELK library provides a logging backend for Apple's apple/swift-log

null 17 Nov 15, 2022
JustLog brings logging on iOS to the next level. It supports console, file and remote Logstash logging via TCP socket with no effort. Support for logz.io available.

JustLog JustLog takes logging on iOS to the next level. It supports console, file and remote Logstash logging via TCP socket with no effort. Support f

Just Eat 509 Dec 10, 2022
Twitter Logging Service is a robust and performant logging framework for iOS clients

Twitter Logging Service Background Twitter created a framework for logging in order to fulfill the following requirements: fast (no blocking the main

Twitter 290 Nov 15, 2022
A flexible logging library written in Swift

Puppy Puppy is a flexible logging library written in Swift ?? It supports multiple transports(console, file, syslog, and oslog) as loggers. It not onl

Koichi Yokota 92 Dec 29, 2022
TraceLog is a highly configurable, flexible, portable, and simple to use debug logging system for Swift and Objective-C applications running on Linux, macOS, iOS, watchOS, and tvOS.

Please star this github repository to stay up to date. TraceLog Introduction TraceLog is a highly configurable, flexible, portable, and simple to use

Tony Stone 52 Oct 28, 2022
Swift Logging Utility for Xcode & Google Docs

QorumLogs Swift Logging Utility in Xcode & Google Docs

Goktug Yilmaz 777 Jul 15, 2022
Logging utility for Swift and Objective C

Swell - Swift Logging A logging utility for Swift and Objective C. ##Features Turn on logging during development, turn them off when building for the

Hubert Rabago 361 Jun 29, 2022
A fast & simple, yet powerful & flexible logging framework for Mac and iOS

CocoaLumberjack CocoaLumberjack is a fast & simple, yet powerful & flexible logging framework for macOS, iOS, tvOS and watchOS. How to get started Fir

null 12.9k Jan 9, 2023
A modern, flexible logging tool

NSLogger NSLogger is a high performance logging utility which displays traces emitted by client applications running on macOS, iOS and Android. It rep

Florent Pillet 5k Dec 22, 2022
Willow is a powerful, yet lightweight logging library written in Swift.

Willow Willow is a powerful, yet lightweight logging library written in Swift. Features Requirements Migration Guides Communication Installation Cocoa

Nike Inc. 1.3k Nov 16, 2022