diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE
new file mode 100644
index 0000000..f1a88e9
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE
@@ -0,0 +1,14 @@
+Hi! Thanks for your interest in contributing to this project.
+
+Clojure contrib projects do not use GitHub issues or pull requests, and
+require a signed Contributor Agreement. If you would like to contribute,
+please read more about the CA and sign that first (this can be done online).
+
+Then go to this project's issue tracker in JIRA to create tickets, update
+tickets, or submit patches. For help in creating tickets and patches,
+please see:
+
+- Contributing FAQ: https://clojure.org/dev
+- Signing the CA: https://clojure.org/dev/contributor_agreement
+- Creating Tickets: https://clojure.org/dev/creating_tickets
+- Developing Patches: https://clojure.org/dev/developing_patches
diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml
new file mode 100644
index 0000000..7bb4d73
--- /dev/null
+++ b/.github/workflows/doc-build.yml
@@ -0,0 +1,13 @@
+name: Build API Docs
+
+permissions:
+ contents: write
+
+on:
+ workflow_dispatch:
+
+jobs:
+ call-doc-build-workflow:
+ uses: clojure/build.ci/.github/workflows/doc-build.yml@master
+ with:
+ project: clojure/tools.logging
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..286cf95
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,22 @@
+name: Release on demand
+
+permissions:
+ contents: write
+
+on:
+ workflow_dispatch:
+ inputs:
+ releaseVersion:
+ description: "Version to release"
+ required: true
+ snapshotVersion:
+ description: "Snapshot version after release"
+ required: true
+
+jobs:
+ call-release:
+ uses: clojure/build.ci/.github/workflows/release.yml@master
+ with:
+ releaseVersion: ${{ github.event.inputs.releaseVersion }}
+ snapshotVersion: ${{ github.event.inputs.snapshotVersion }}
+ secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml
new file mode 100644
index 0000000..9fdad8c
--- /dev/null
+++ b/.github/workflows/snapshot.yml
@@ -0,0 +1,11 @@
+name: Snapshot on demand
+
+permissions:
+ contents: read
+
+on: [workflow_dispatch]
+
+jobs:
+ call-snapshot:
+ uses: clojure/build.ci/.github/workflows/snapshot.yml@master
+ secrets: inherit
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..2cc441a
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,10 @@
+name: Test
+
+permissions:
+ contents: read
+
+on: [push]
+
+jobs:
+ call-test:
+ uses: clojure/build.ci/.github/workflows/test.yml@master
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 356aa84..68461d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,16 +5,71 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
([despite its flaws](https://www.youtube.com/watch?v=oyLBGkS5ICk)).
-## [Unreleased]
+## [1.3.1] - 2025-12-30
+
+### Changed
+
+- Bumped parent pom to 1.4.0
+- Bumped deps to Clojure 1.11.4
+- Bumped test deps to latest
+
+## [1.3.0] - 2024-02-06
+
+### Changed
+- TLOG-28 - Moved slf4j test deps to 2.0.6
+- Bumped Clojure dep to 1.10.3
+
+## [1.2.4] - 2022-01-04
+
+### Changed
+- Bumped log4j test deps to 2.17.1
+
+## [1.2.3] - 2021-12-18
+
+### Changed
+- Bumped log4j test deps to 2.17.0
+
+## [1.2.2] - 2021-12-14
+
+### Changed
+- Bumped log4j test deps to 2.16.0
+
+## [1.2.1] - 2021-12-10
+
+### Changed
+- Bumped all testing deps to latest (particularly log4j)
+
+## [1.2.0] - 2021-12-10
+
+### Changed
+- Bumped all testing deps to latest (particularly log4j)
+
+## [1.1.0] - 2020-04-25
+### Added
+- Add implementation of `spyf` to `clojure.tools.logging.readable`.
+
+### Changed
+- Decreased the per-call overhead when using SLF4J, Commons Logging, and Log4j2.
+ Previously, their associated `logger-factory` implementations were calling
+ library-specific static convenience methods for each call to `get-logger`.
+ These methods have some baked-in setup overhead, which now only occurs during
+ instantiation of the associated `logger-factory`.
+
+## [1.0.0] - 2020-02-27
+### Added
+- Add support for printing message arguments readably in
+ [`clojure.tools.logging.readable`](https://clojure.github.io/tools.logging/#clojure.tools.logging.readable).
## [0.6.0] - 2020-02-07
### Added
- Add support for explicitly selecting a logger factory by setting the
- `clojure.tools.logging.factory` system property.
+ `"clojure.tools.logging.factory"` system property. For details, see the
+ [README](https://github.com/clojure/tools.logging#configuration),
+ and the documentation for [\*logger-factory\*](https://clojure.github.io/tools.logging/#clojure.tools.logging/*logger-factory*).
## [0.5.0] - 2019-07-22
### Added
-- Add support for testing logs in `clojure.tools.logging.test`
+- Add support for testing logs in [`clojure.tools.logging.test`](https://clojure.github.io/tools.logging/#clojure.tools.logging.test).
### Changed
- Now passes the context classloader of current thread to `Class/forName` when
@@ -78,7 +133,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added
- Initial implementation of Clojure-aware logging abstraction.
-[Unreleased]: https://github.com/clojure/tools.logging/compare/tools.logging-0.6.0...HEAD
+[Unreleased]: https://github.com/clojure/tools.logging/compare/tools.logging-1.1.0...HEAD
+[1.3.1]: https://github.com/clojure/tools.logging/compare/v1.3.0...v1.3.1
+[1.3.0]: https://github.com/clojure/tools.logging/compare/v1.2.4...v1.3.0
+[1.2.4]: https://github.com/clojure/tools.logging/compare/v1.2.3...v1.2.4
+[1.2.3]: https://github.com/clojure/tools.logging/compare/v1.2.2...v1.2.3
+[1.2.2]: https://github.com/clojure/tools.logging/compare/v1.2.1...v1.2.2
+[1.2.1]: https://github.com/clojure/tools.logging/compare/v1.2.0...v1.2.1
+[1.2.0]: https://github.com/clojure/tools.logging/compare/tools.logging-1.1.0...v1.2.0
+[1.1.0]: https://github.com/clojure/tools.logging/compare/tools.logging-1.0.0...tools.logging-1.1.0
+[1.0.0]: https://github.com/clojure/tools.logging/compare/tools.logging-0.6.0...tools.logging-1.0.0
[0.6.0]: https://github.com/clojure/tools.logging/compare/tools.logging-0.5.0...tools.logging-0.6.0
[0.5.0]: https://github.com/clojure/tools.logging/compare/tools.logging-0.4.1...tools.logging-0.5.0
[0.4.1]: https://github.com/clojure/tools.logging/compare/tools.logging-0.4.0...tools.logging-0.4.1
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d91a363..26313e3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,5 +8,5 @@ more information on how to contribute.
[Clojure contrib]: https://clojure.org/community/contrib_libs
[Contributing]: https://clojure.org/community/contributing
-[JIRA]: http://dev.clojure.org/jira/browse/TLOG
+[JIRA]: https://clojure.atlassian.net/browse/TLOG
[guidelines]: https://clojure.org/community/contrib_howto
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e246f6a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,205 @@
+Eclipse Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
+CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation
+ distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+ i) changes to the Program, and
+ ii) additions to the Program;
+
+ where such changes and/or additions to the Program originate from and are
+ distributed by that particular Contributor. A Contribution 'originates'
+ from a Contributor if it was added to the Program by such Contributor
+ itself or anyone acting on such Contributor's behalf. Contributions do not
+ include additions to the Program which: (i) are separate modules of
+ software distributed in conjunction with the Program under their own
+ license agreement, and (ii) are not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which are
+necessarily infringed by the use or sale of its Contribution alone or when
+combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement,
+including all Contributors.
+
+2. GRANT OF RIGHTS
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
+ Recipient a non-exclusive, worldwide, royalty-free copyright license to
+ reproduce, prepare derivative works of, publicly display, publicly
+ perform, distribute and sublicense the Contribution of such Contributor,
+ if any, and such derivative works, in source code and object code form.
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
+ Recipient a non-exclusive, worldwide, royalty-free patent license under
+ Licensed Patents to make, use, sell, offer to sell, import and otherwise
+ transfer the Contribution of such Contributor, if any, in source code and
+ object code form. This patent license shall apply to the combination of
+ the Contribution and the Program if, at the time the Contribution is
+ added by the Contributor, such addition of the Contribution causes such
+ combination to be covered by the Licensed Patents. The patent license
+ shall not apply to any other combinations which include the Contribution.
+ No hardware per se is licensed hereunder.
+ c) Recipient understands that although each Contributor grants the licenses
+ to its Contributions set forth herein, no assurances are provided by any
+ Contributor that the Program does not infringe the patent or other
+ intellectual property rights of any other entity. Each Contributor
+ disclaims any liability to Recipient for claims brought by any other
+ entity based on infringement of intellectual property rights or
+ otherwise. As a condition to exercising the rights and licenses granted
+ hereunder, each Recipient hereby assumes sole responsibility to secure
+ any other intellectual property rights needed, if any. For example, if a
+ third party patent license is required to allow Recipient to distribute
+ the Program, it is Recipient's responsibility to acquire that license
+ before distributing the Program.
+ d) Each Contributor represents that to its knowledge it has sufficient
+ copyright rights in its Contribution, if any, to grant the copyright
+ license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under
+its own license agreement, provided that:
+
+ a) it complies with the terms and conditions of this Agreement; and
+ b) its license agreement:
+ i) effectively disclaims on behalf of all Contributors all warranties
+ and conditions, express and implied, including warranties or
+ conditions of title and non-infringement, and implied warranties or
+ conditions of merchantability and fitness for a particular purpose;
+ ii) effectively excludes on behalf of all Contributors all liability for
+ damages, including direct, indirect, special, incidental and
+ consequential damages, such as lost profits;
+ iii) states that any provisions which differ from this Agreement are
+ offered by that Contributor alone and not by any other party; and
+ iv) states that source code for the Program is available from such
+ Contributor, and informs licensees how to obtain it in a reasonable
+ manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+ a) it must be made available under this Agreement; and
+ b) a copy of this Agreement must be included with each copy of the Program.
+ Contributors may not remove or alter any copyright notices contained
+ within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution,
+if
+any, in a manner that reasonably allows subsequent Recipients to identify the
+originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with
+respect to end users, business partners and the like. While this license is
+intended to facilitate the commercial use of the Program, the Contributor who
+includes the Program in a commercial product offering should do so in a manner
+which does not create potential liability for other Contributors. Therefore,
+if a Contributor includes the Program in a commercial product offering, such
+Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+every other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits and
+other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such Commercial
+Contributor in connection with its distribution of the Program in a commercial
+product offering. The obligations in this section do not apply to any claims
+or Losses relating to any actual or alleged intellectual property
+infringement. In order to qualify, an Indemnified Contributor must:
+a) promptly notify the Commercial Contributor in writing of such claim, and
+b) allow the Commercial Contributor to control, and cooperate with the
+Commercial Contributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such claim at
+its own expense.
+
+For example, a Contributor might include the Program in a commercial product
+offering, Product X. That Contributor is then a Commercial Contributor. If
+that Commercial Contributor then makes performance claims, or offers
+warranties related to Product X, those performance claims and warranties are
+such Commercial Contributor's responsibility alone. Under this section, the
+Commercial Contributor would have to defend claims against the other
+Contributors related to those performance claims and warranties, and if a
+court requires any other Contributor to pay any damages as a result, the
+Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
+Recipient is solely responsible for determining the appropriateness of using
+and distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to the
+risks and costs of program errors, compliance with applicable laws, damage to
+or loss of data, programs or equipment, and unavailability or interruption of
+operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
+LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of the
+remainder of the terms of this Agreement, and without further action by the
+parties hereto, such provision shall be reformed to the minimum extent
+necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program itself
+(excluding combinations of the Program with other software or hardware)
+infringes such Recipient's patent(s), then such Recipient's rights granted
+under Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to
+comply with any of the material terms or conditions of this Agreement and does
+not cure such failure in a reasonable period of time after becoming aware of
+such noncompliance. If all Recipient's rights under this Agreement terminate,
+Recipient agrees to cease use and distribution of the Program as soon as
+reasonably practicable. However, Recipient's obligations under this Agreement
+and any licenses granted by Recipient relating to the Program shall continue
+and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in
+order to avoid inconsistency the Agreement is copyrighted and may only be
+modified in the following manner. The Agreement Steward reserves the right to
+publish new versions (including revisions) of this Agreement from time to
+time. No one other than the Agreement Steward has the right to modify this
+Agreement. The Eclipse Foundation is the initial Agreement Steward. The
+Eclipse Foundation may assign the responsibility to serve as the Agreement
+Steward to a suitable separate entity. Each new version of the Agreement will
+be given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new version of the
+Agreement is published, Contributor may elect to distribute the Program
+(including its Contributions) under the new version. Except as expressly
+stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
+licenses to the intellectual property of any Contributor under this Agreement,
+whether expressly, by implication, estoppel or otherwise. All rights in the
+Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the
+intellectual property laws of the United States of America. No party to this
+Agreement will bring a legal action under this Agreement more than one year
+after the cause of action arose. Each party waives its rights to a jury trial in
+any resulting litigation.
+
+
diff --git a/README.md b/README.md
index b49fb77..b4eba9f 100644
--- a/README.md
+++ b/README.md
@@ -5,12 +5,17 @@ at runtime when the `clojure.tools.logging` namespace is first loaded.
## Installation
-Lastest stable release is [0.6.0]
+Lastest stable release is [1.3.1]
+
+[CLI/`deps.edn`](https://clojure.org/reference/deps_edn) dependency information:
+```clojure
+org.clojure/tools.logging {:mvn/version "1.3.1"}
+```
Leiningen:
```clojure
-[org.clojure/tools.logging "0.6.0"]
+[org.clojure/tools.logging "1.3.1"]
```
Maven:
@@ -19,43 +24,36 @@ Maven:
org.clojure
tools.logging
- 0.6.0
+ 1.3.1
```
-Gradle:
-
-```clojure
-compile "org.clojure:tools.logging:0.6.0"
-```
-
-
## Usage
-[Latest API Documentation](http://clojure.github.com/tools.logging)
+[Latest API Documentation](https://clojure.github.io/tools.logging)
Logging occurs with the `log` macro, or the level-specific convenience macros
(e.g., `debug`, `debugf`). Only when the specified logging level is enabled will
the message arguments be evaluated and the underlying logging implementation be
-invoked. By default that invocation will occur via an agent when inside a running
-STM transaction.
+invoked. By default, that invocation will occur via an agent when inside a
+running STM transaction.
### Namespacing of log entries
Unless otherwise specified, the current namespace (as identified by `*ns*`) will
-be used as the log-ns. This value can be emitted in the log entry, and used by most
-logging implementations when using namespace-specific logging levels.
+be used as the "logger name" when interacting with logging implementations. Most
+logging implementations allow for varying configuration by logger name.
-Note: You should configure your logging implementation to display the name that
-was passed to it. If it instead performs stack-inspection you'll see some ugly
-and unhelpful text in your logs.
+Note: You should configure your logging implementation to display the logger
+name that was passed to it. If instead the logging implementation performs
+stack-inspection you'll see some ugly and unhelpful text in your logs.
### Redirecting output to logs
You can redirect all java writes of `System.out` and `System.err` to the log
system by calling `log-capture!`. To bind `*out*` and `*err*` to the log system
-invoke `with-logs`. In both cases a log-ns value must be specified in order to
-namespace the output.
+invoke `with-logs`. In both cases a logger name must be provided in lieu of
+using `*ns*`.
## Configuration
@@ -68,7 +66,8 @@ library._
To control which logging implementation is used, set the `clojure.tools.logging.factory`
system property to the fully-qualified name of a no-arg function that returns an
instance of `clojure.tools.logging.impl/LoggerFactory`. There are a number of
-factory functions provided in the `clojure.tools.logging.impl` namespace.
+factory functions provided in the [`clojure.tools.logging.impl`](https://clojure.github.io/tools.logging/#clojure.tools.logging.impl/find-factory)
+namespace.
[Leiningen example]:
@@ -89,6 +88,37 @@ The above approach is problematic given that applications often inadvertently pu
in multiple logging implementations as transitive dependencies. As such, it is
_strongly_ advised that you set the system property.
+### Log4J2
+
+A simple Log4j2 [configuration](https://logging.apache.org/log4j/2.x/manual/configuration.html):
+
+```properties
+status = warn
+monitorInterval = 5
+
+appender.console.type = Console
+appender.console.name = STDOUT
+appender.console.layout.type = PatternLayout
+appender.console.layout.pattern = %date %level %logger %message%n%throwable
+
+rootLogger.level = info
+rootLogger.appenderRef.stdout.ref = STDOUT
+```
+
+*Note:* The above [pattern](https://logging.apache.org/log4j/2.x/manual/layouts.html#Patterns)
+explicitly uses `%throwable` so that `clojure.lang.ExceptionInfo` exceptions
+will be printed with their data maps. If either `%xThrowable` (the default) or
+`%rThrowable` is used, the data maps will not be printed.
+
+## FAQ
+
+#### When logging an `ex-info` exception, why isn't the data map printed?
+
+This is likely because the logging implementation is printing the contents of
+`Throwable.getMessage()`, which returns just the message arg to `ex-info`.
+
+Logging implementations that print the contents of `toString()` or use `Throwable.printStackTrace(...)`
+will end up printing the data map.
## Thanks
@@ -100,15 +130,17 @@ _strongly_ advised that you set the system property.
## License
-Copyright © 2009 Alex Taggart
+Copyright © Rich Hickey, Alex Taggart, and contributors
Licensed under the EPL. (See the file epl.html.)
-[0.6.0]: https://github.com/clojure/tools.logging/tree/tools.logging-0.6.0
+[1.3.1]: https://github.com/clojure/tools.logging/tree/v1.3.1
+[1.3.0]: https://github.com/clojure/tools.logging/tree/v1.3.0
+[1.2.4]: https://github.com/clojure/tools.logging/tree/v1.2.4
[Leiningen example]: https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#setting-jvm-options
-[SLF4J]: http://www.slf4j.org/
+[SLF4J]: https://www.slf4j.org/
[Apache Commons Logging]: https://commons.apache.org/logging
[Log4J 2]: https://logging.apache.org/log4j/2.x/
-[Log4J]: http://logging.apache.org/log4j/1.2/
+[Log4J]: https://logging.apache.org/log4j/1.2/
[java.util.logging]: https://docs.oracle.com/en/java/javase/13/docs/api/java.logging/java/util/logging/package-summary.html
diff --git a/pom.xml b/pom.xml
index bcf7bb3..5d3d47b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,13 +1,14 @@
4.0.0
tools.logging
- 0.6.1-SNAPSHOT
+ 1.3.2-SNAPSHOT
tools.logging
+ Clojure logging API.
org.clojure
pom.contrib
- 0.2.2
+ 1.4.0
@@ -23,41 +24,39 @@
HEAD
+
+ 1.11.4
+
+
org.slf4j
slf4j-api
- 1.6.2
+ 2.0.17
test
org.slf4j
- slf4j-log4j12
- 1.6.2
- test
-
-
- log4j
- log4j
- 1.2.16
+ slf4j-reload4j
+ 2.0.17
test
org.apache.logging.log4j
log4j-api
- 2.8.2
+ 2.25.3
test
org.apache.logging.log4j
log4j-core
- 2.8.2
+ 2.25.3
test
commons-logging
commons-logging
- 1.1.1
+ 1.3.5
test
diff --git a/project.clj b/project.clj
index c3c610e..393d661 100644
--- a/project.clj
+++ b/project.clj
@@ -1,18 +1,18 @@
-(defproject org.clojure/tools.logging "0.6.1-SNAPSHOT"
+(defproject org.clojure/tools.logging "1.1.1-SNAPSHOT"
:description "Clojure logging API."
:url "https://github.com/clojure/tools.logging"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:source-paths ["src/main/clojure"]
:test-paths ["src/test/clojure"]
- :dependencies [[org.clojure/clojure "1.3.0"]]
+ :dependencies [[org.clojure/clojure "1.11.4"]]
:aliases {"cloverage" ["with-profile" "dev,cloverage" "cloverage" "--fail-threshold" "100"]}
- :profiles {:cloverage {:plugins [[lein-cloverage "1.0.9"]]}
- :dev {:dependencies [[org.clojure/clojure "1.8.0"]
- [org.clojure/test.check "0.9.0"]
- [org.slf4j/slf4j-api "1.6.2"]
- [org.slf4j/slf4j-log4j12 "1.6.2"]
- [log4j "1.2.16"]
- [org.apache.logging.log4j/log4j-api "2.8.2"]
- [org.apache.logging.log4j/log4j-core "2.8.2"]
- [commons-logging "1.1.1"]]}})
+ :profiles {:cloverage {:plugins [[lein-cloverage "1.2.4"]]}
+ :dev {:dependencies [[org.clojure/clojure "1.11.4"]
+ [org.clojure/test.check "1.1.2"]
+ [org.slf4j/slf4j-api "2.0.17"]
+ [org.slf4j/slf4j-log4j12 "2.0.17"]
+ [org.apache.logging.log4j/log4j-api "2.25.3"]
+ [org.apache.logging.log4j/log4j-core "2.25.3"]
+ [commons-logging "1.3.5"]
+ [criterium "0.4.6"]]}})
diff --git a/src/main/clojure/clojure/tools/logging.clj b/src/main/clojure/clojure/tools/logging.clj
index b4cc2d3..e963f06 100644
--- a/src/main/clojure/clojure/tools/logging.clj
+++ b/src/main/clojure/clojure/tools/logging.clj
@@ -81,7 +81,8 @@
(defmacro logp
"Logs a message using print style args. Can optionally take a throwable as its
- second arg. See level-specific macros, e.g., debug."
+ second arg. See level-specific macros, e.g., debug.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([level message & more] [level throwable message & more])}
[level x & more]
(if (or (instance? String x) (nil? more)) ; optimize for common case
@@ -95,7 +96,8 @@
(defmacro logf
"Logs a message using a format string and args. Can optionally take a
- throwable as its second arg. See level-specific macros, e.g., debugf."
+ throwable as its second arg. See level-specific macros, e.g., debugf.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([level fmt & fmt-args] [level throwable fmt & fmt-args])}
[level x & more]
(if (or (instance? String x) (nil? more)) ; optimize for common case
@@ -134,7 +136,8 @@
(defmacro spyf
"Evaluates expr and may write (format fmt result) to the log. Returns the
- result of expr. Defaults to :debug log level."
+ result of expr. Defaults to :debug log level.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
([fmt expr]
`(spyf :debug ~fmt ~expr))
([level fmt expr]
@@ -211,73 +214,85 @@
;; level-specific macros
(defmacro trace
- "Trace level logging using print-style args."
+ "Trace level logging using print-style args.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :trace ~@args))
(defmacro debug
- "Debug level logging using print-style args."
+ "Debug level logging using print-style args.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :debug ~@args))
(defmacro info
- "Info level logging using print-style args."
+ "Info level logging using print-style args.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :info ~@args))
(defmacro warn
- "Warn level logging using print-style args."
+ "Warn level logging using print-style args.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :warn ~@args))
(defmacro error
- "Error level logging using print-style args."
+ "Error level logging using print-style args.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :error ~@args))
(defmacro fatal
- "Fatal level logging using print-style args."
+ "Fatal level logging using print-style args.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :fatal ~@args))
(defmacro tracef
- "Trace level logging using format."
+ "Trace level logging using format.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :trace ~@args))
(defmacro debugf
- "Debug level logging using format."
+ "Debug level logging using format.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :debug ~@args))
(defmacro infof
- "Info level logging using format."
+ "Info level logging using format.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :info ~@args))
(defmacro warnf
- "Warn level logging using format."
+ "Warn level logging using format.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :warn ~@args))
(defmacro errorf
- "Error level logging using format."
+ "Error level logging using format.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :error ~@args))
(defmacro fatalf
- "Fatal level logging using format."
+ "Fatal level logging using format.
+ Use the 'logging.readable' namespace to avoid wrapping args in pr-str."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :fatal ~@args))
diff --git a/src/main/clojure/clojure/tools/logging/impl.clj b/src/main/clojure/clojure/tools/logging/impl.clj
index 087b190..cac7fb1 100644
--- a/src/main/clojure/clojure/tools/logging/impl.clj
+++ b/src/main/clojure/clojure/tools/logging/impl.clj
@@ -61,7 +61,8 @@
[]
(when (class-found? "org.slf4j.Logger")
(eval
- `(do
+ `(let [; Same as is done inside LoggerFactory/getLogger(String).
+ factory# (org.slf4j.LoggerFactory/getILoggerFactory)]
(extend org.slf4j.Logger
Logger
{:enabled?
@@ -98,7 +99,7 @@
(name [_#]
"org.slf4j")
(get-logger [_# logger-ns#]
- (org.slf4j.LoggerFactory/getLogger ^String (str logger-ns#))))))))
+ (.getLogger factory# ^String (str logger-ns#))))))))
(defn cl-factory
"Returns a Commons Logging-based implementation of the LoggerFactory protocol, or
@@ -106,7 +107,8 @@
[]
(when (class-found? "org.apache.commons.logging.Log")
(eval
- `(do
+ `(let [; Same as is done inside LogFactory/getLog(String).
+ factory# (org.apache.commons.logging.LogFactory/getFactory)]
(extend org.apache.commons.logging.Log
Logger
{:enabled?
@@ -142,7 +144,7 @@
(name [_#]
"org.apache.commons.logging")
(get-logger [_# logger-ns#]
- (org.apache.commons.logging.LogFactory/getLog (str logger-ns#))))))))
+ (.getInstance factory# (str logger-ns#))))))))
(defn log4j-factory
"Returns a Log4j-based implementation of the LoggerFactory protocol, or nil if
@@ -179,7 +181,9 @@
[]
(when (class-found? "org.apache.logging.log4j.Logger")
(eval
- `(let [levels# {:trace org.apache.logging.log4j.Level/TRACE
+ `(let [; Same as is done inside LogManager/getLogger(String).
+ context# (org.apache.logging.log4j.LogManager/getContext false)
+ levels# {:trace org.apache.logging.log4j.Level/TRACE
:debug org.apache.logging.log4j.Level/DEBUG
:info org.apache.logging.log4j.Level/INFO
:warn org.apache.logging.log4j.Level/WARN
@@ -206,7 +210,7 @@
(name [_#]
"org.apache.logging.log4j")
(get-logger [_# logger-ns#]
- (org.apache.logging.log4j.LogManager/getLogger ^String (str logger-ns#))))))))
+ (.getLogger context# ^String (str logger-ns#))))))))
(defn jul-factory
"Returns a java.util.logging-based implementation of the LoggerFactory protocol,
diff --git a/src/main/clojure/clojure/tools/logging/readable.clj b/src/main/clojure/clojure/tools/logging/readable.clj
index b1c9465..b69b1c5 100644
--- a/src/main/clojure/clojure/tools/logging/readable.clj
+++ b/src/main/clojure/clojure/tools/logging/readable.clj
@@ -7,7 +7,10 @@
;; remove this notice, or any other, from this software.
(ns ^{:author "Alex Taggart"
- :doc "Logging macros that support printing message arguments readably.
+ :doc "Logging macros that support printing message (some) arguments as
+ if wrapped in pr-str, the goal being to preserve their data representation
+ distinct from the explanatory text. See logp and logf for details regarding
+ which args are treated in this manner.
Examples:
@@ -15,7 +18,7 @@
'[clojure.tools.logging.readable :as logr])
(def x \"bar\")
- ; Logged as...
+ ; Logged as...
(log/debug \"foo\" x \"baz\") ; foo bar baz
(logr/debug \"foo\" x \"baz\") ; foo \"bar\" baz
(log/debugf \"foo %s %s\" x \"baz\") ; foo bar baz
@@ -33,8 +36,9 @@
(defmacro logp
"Logs a message using print style args, where message args that are not
- literal strings will be printed readably. Can optionally take a throwable as
- its second arg. See level-specific macros, e.g., debug."
+ literal strings will be printed readably, as if wrapped in pr-str. Can
+ optionally take a throwable as its second arg. See level-specific macros,
+ e.g., debug."
{:arglists '([level message & more] [level throwable message & more])}
[level x & more]
; Why bind `*print-readably*` to true?
@@ -65,8 +69,8 @@
(defmacro logf
"Logs a message using a format string and args, where all format args will be
- printed readably. Can optionally take a throwable as its second arg. See
- level-specific macros, e.g., debugf."
+ printed readably, as if wrapped in pr-str. Can optionally take a throwable as
+ its second arg. See level-specific macros, e.g., debugf."
{:arglists '([level fmt & fmt-args] [level throwable fmt & fmt-args])}
[level x & more]
(if (or (instance? String x) (nil? more)) ; optimize for non-exception case
@@ -155,3 +159,13 @@
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :fatal ~@args))
+
+(defmacro spyf
+ "Evaluates expr and may write (logf level fmt result) to the log. Returns the
+ result of expr. Defaults to :debug log level."
+ ([fmt expr]
+ `(spyf :debug ~fmt ~expr))
+ ([level fmt expr]
+ `(let [a# ~expr]
+ (logf ~level ~fmt a#)
+ a#)))
diff --git a/src/main/clojure/clojure/tools/logging/test.clj b/src/main/clojure/clojure/tools/logging/test.clj
index 9c9087f..19a8ff4 100644
--- a/src/main/clojure/clojure/tools/logging/test.clj
+++ b/src/main/clojure/clojure/tools/logging/test.clj
@@ -18,9 +18,9 @@
(with-log
(log/info \"Hello World!\")
(log/error (Exception. \"Did a thing\") \"Error: oops\")
- (logged? 'user :info #\"Hello\") ; true
+ (logged? 'user :info #\"Hello\") ; true
(logged? 'user :error [Throwable #\"thing\"] #\"Error:\") ; true
- (logged? 'user :debug \"Hi\")) ; false"}
+ (logged? 'user :debug \"Hi\")) ; false"}
clojure.tools.logging.test
(:import [clojure.lang Fn Keyword Namespace Symbol]
java.util.Set
@@ -227,7 +227,9 @@
(defn matches
- "Returns matching log entries, otherwise nil.
+ "Returns matching log entries, otherwise nil. See match-logger-ns?,
+ match-level?, match-throwable?, and match-message? for the default matching
+ behavior applied to the given args.
Must be invoked within a context where *stateful-log* is bound to an instance
of StatefulLog containing MatchableLogEntry items (e.g., inside with-log)."
@@ -239,7 +241,9 @@
(defn logged?
- "Returns true if the log contains matching entries.
+ "Returns true if the log contains matching entries. See match-logger-ns?,
+ match-level?, match-throwable?, and match-message? for the default matching
+ behavior applied to the given args.
Must be invoked within a context where *stateful-log* is bound to an instance
of StatefulLog containing MatchableLogEntry items (e.g., inside with-log)."
diff --git a/src/test/clojure/clojure/tools/logging/test_readable.clj b/src/test/clojure/clojure/tools/logging/test_readable.clj
index e2bc401..3ba09e2 100644
--- a/src/test/clojure/clojure/tools/logging/test_readable.clj
+++ b/src/test/clojure/clojure/tools/logging/test_readable.clj
@@ -188,6 +188,18 @@
(is (logged? "clojure.tools.logging.test-readable" :debug e "hello \"world\"")))))
+(deftest spyf-default
+ (with-log
+ (spyf "result: %s" (str "hello" " " "world"))
+ (is (logged? "clojure.tools.logging.test-readable" :debug nil "result: \"hello world\""))))
+
+(deftest spyf-level
+ (doseq [level #{:trace :debug :info :warn :error :fatal}]
+ (with-log
+ (spyf level "result: %s" (str "hello" " " "world"))
+ (is (logged? "clojure.tools.logging.test-readable" level nil "result: \"hello world\"")))))
+
+
(deftest println-style
(are [f kw] (with-log
(f "hello" "world")