{"id":22416099,"url":"https://github.com/appunite/spy","last_synced_at":"2025-08-01T01:30:50.057Z","repository":{"id":42443678,"uuid":"235777243","full_name":"appunite/Spy","owner":"appunite","description":"Spy is a flexible, lightweight, multiplatform logging utility written in pure Swift. It allows to log with different levels and on different channels. You can define what levels and channels actually are.","archived":false,"fork":false,"pushed_at":"2022-07-22T05:06:55.000Z","size":536,"stargazers_count":13,"open_issues_count":3,"forks_count":0,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-12-01T03:40:30.087Z","etag":null,"topics":["ios","logger","logging","macos","osx","swift","tvos","watchos"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/appunite.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-01-23T11:02:53.000Z","updated_at":"2024-07-16T11:21:24.000Z","dependencies_parsed_at":"2022-08-20T07:20:54.929Z","dependency_job_id":null,"html_url":"https://github.com/appunite/Spy","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appunite%2FSpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appunite%2FSpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appunite%2FSpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appunite%2FSpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appunite","download_url":"https://codeload.github.com/appunite/Spy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228321226,"owners_count":17901604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","logger","logging","macos","osx","swift","tvos","watchos"],"created_at":"2024-12-05T15:14:37.037Z","updated_at":"2024-12-05T15:14:37.758Z","avatar_url":"https://github.com/appunite.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/appunite/Spy.svg?branch=master)](https://travis-ci.org/appunite/Spy)\n[![codecov](https://codecov.io/gh/appunite/Spy/branch/master/graph/badge.svg)](https://codecov.io/gh/appunite/Spy)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-Compatible-brightgreen.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Cocoapods](https://img.shields.io/cocoapods/v/Spy.svg?style=flat)](https://cocoapods.org/pods/Spy)\n[![Platform](https://img.shields.io/cocoapods/p/Spy.svg?style=flat)](https://cocoapods.org/pods/Spy)\n[![Platform](https://img.shields.io/badge/Platform-linux-brightgreen.svg)](#)\n[![License](https://img.shields.io/cocoapods/l/Spy.svg?style=flat)](https://cocoapods.org/pods/Spy)\n\n\nSpy 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.\n\n## Requirements\n\n### Development\nProject uses following tools for development\n1. [XCodeGen](https://github.com/yonaskolb/XcodeGen)\n2. [Cocoapods](https://cocoapods.org)\n3. [SwiftLint](https://github.com/realm/SwiftLint)\n4. [Sourcery](https://github.com/krzysztofzablocki/Sourcery)\n\n## Installation\n\nTo get started with the **Spy** you first have to decide how you will integrate it with your project. Spy supports following tools:\n\n### Cocoapods\n\nTo install Spy using Cocoapods go through following steps:\n\n1. Add the following entry in your **Podfile**:\n```\npod 'Spy'\n```\n2. Then run `pod install`.\n\n\n### Carthage\n\nTo install Spy using Carthage go through following steps:\n\n1. Add the following entry to your **Cartfile**\n\n```\ngithub \"appunite/Spy\"\n```\n\n2. Then run ```carthage update```\n\n### Swift Package Manager\n\nTo install Spy using **Swift Package Manager** go through following steps:\n\n1. Add following package dependency in you **Package.swift** ``` .package(url: \"https://github.com/appunite/Spy.git\", from: \"0.5.0\") ```\n2. Add following target dependency in your **Package.swift** ``` dependencies: [\"Spy\"]) ```\n\nFor instance this is how it might look like:\n```swift\nimport PackageDescription\n\nlet package = Package(\n    name: \"YourLibrary\",\n    products: [\n        .library(\n            name: \"YourLibrary\",\n            targets: [\"YourLibrary\"])\n    ],\n    dependencies: [\n        .package(url: \"https://github.com/appunite/Spy.git\", from: \"0.5.0\")\n    ],\n    targets: [\n        .target(\n            name: \"YourLibrary\",\n            dependencies: [\"Spy\"])\n    ]\n)\n```\n\n## Overview\n\nHere is a quick overview of functionalities and concepts used in **Spy**.\n\n### SpyChannel\n\nSpyChannel 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:\n```swift\npublic enum SpyChannel: String, PSpyChannel {\n    case foo\n    case bar\n    \n    public var channelName: String {\n        return self.rawValue\n    }\n}\n```\n\n### SpyLevel\nSpyLevel 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.\n\n### SpyConfiguration\nContains levels and channels that the Spy will spy on.\n\n### SpyConfigurationBuilder\nBuilds your spy configuration by providing add and remove functions for both levels and channels.\nExample usage:\n```swift\nSpyConfigurationBuilder()\n    .add(level: .severe)\n    .add(channels: [.foo, .bar])\n    .build()\n```\n\n### Spyable\nSpyable 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.\n\n### Spied\nSpied is a property wrapper that allows to log all changes and accesses to a property. Example usage:\n```swift\nclass Foo {\n    @Spied(spy: Environment.spy, onLevel: .info, onChannel: .foo) var foo = \"foo\"\n}\n```\n\n### Spy\nSpy is anything that implements *PSpy* protocol. There are a few spies already defined for you:\n- *ConsoleSpy* - spy that logs spyables by using print command\n- *FileSpy* - spy that logs spyables into the filesystem (allows to create *monolith* or *chunked* logs)\n- *CompositeSpy* - spy that groups multiple spies into one\n- *AnySpy* - type-erased spy - every spy can be converted to AnySpy\n\nLogging is performed with **log** method as follows:\n```swift\nspy.log(level: .severe, channel: .foo, message: \"Something bad happened\")\n```\n\n#### ConsoleSpy\nConsoleSpy comes with two available output formatters **RawSpyFormatter** and **DecoratedSpyFormatter** with the later being extendable with decorators. You can always define your own output formatter.\nExample output for *RawSpyFormatter* will look like:\n```\ninfo::foo::Hello Spy\n```\nAnd example output for *DecoratedSpyFormatter* may look like:\n```\nℹ️ info::foo::Hello Spy\n```\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"resources/log.png\" alt=\"Log example\"/\u003e\n\u003c/p\u003e\n\n## Example\nThis is an example definition of the spies.\nIt utilizes *CompositeSpy* to allow you to log onto multiple destinations (*Console* and *File*).\n```swift\npublic static var spy: AnySpy\u003cSpyLevel, SpyChannel\u003e = {\n    return CompositeSpy()\n        .add(spy: ConsoleSpy\u003cSpyLevel, SpyChannel, DecoratedSpyFormatter\u003e(\n            spyFormatter: DecoratedSpyFormatter(\n                levelNameBuilder: DecoratedLevelNameBuilder\u003cSpyLevel\u003e()\n                    .add(decorator: EmojiPrefixedSpyLevelNameDecorator().any())\n                    ),\n            timestampProvider: CurrentTimestampProvider(),\n            configuration: SpyConfigurationBuilder()\n                .add(levels: SpyLevel.levelsFrom(loggingLevel))\n                .add(channel: .foo)\n            .build()).any())\n        .add(spy: FileSpy\u003cSpyLevel, SpyChannel, DecoratedSpyFormatter\u003e(\n            logFile: LogFile(\n                type: .chunked(maxLogsPerFile: 3),\n                directoryURL: logDirectoryURL),\n            spyFormatter: DecoratedSpyFormatter(\n                levelNameBuilder: DecoratedLevelNameBuilder\u003cSpyLevel\u003e()\n                    .add(decorator: EmojiPrefixedSpyLevelNameDecorator().any())\n            ),\n            timestampProvider: CurrentTimestampProvider(),\n            configuration: SpyConfigurationBuilder()\n                .add(level: .severe)\n                .add(channels: [.foo, .bar])\n                .build()).safe().any()\n        ).any()\n}()\n```\nBy 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.\n```swift    \npublic extension Environment {\n\tstatic var loggingLevel: SpyLevel {\n        #if DEBUG\n        return .info\n        #else\n        return .warning\n        #endif\n    }\n}\n```\n\nAnd here is how you could use Spy:\n```swift\nEnvironment.spy.log(level: .info, channel: .foo, message: \"Hello Spy\")\n```\n\nFor more detailed example please see the source code.\n\n## Contribution\n\nProject is created and maintained by **Tomasz Lewandowski**.\n\nIf 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.\n\n## License\n\nSpy is released under an MIT license. See [License.md](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappunite%2Fspy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappunite%2Fspy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappunite%2Fspy/lists"}