commit 0dcaf740aa36df70b07db58124b96b79403a1ba0 Author: ElBe <90863907+ElBe-Plaq@users.noreply.github.com> Date: Tue Oct 24 09:33:46 2023 +0200 Update to version 1.0.0 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c7e631c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# Editorconfig to keep settings the same across devices and editors +# https://editorconfig.org/ + +root = true + +[*] +charset = utf-8 +indent_style = tab +insert_final_newline = true +tab_width = 4 +trim_trailing_whitespace = true + +[*.{html,md,py,rs}] +indent_size = 4 +indent_style = space + +[*.{yml,yaml}] +indent_style = space diff --git a/.github/.gitlint b/.github/.gitlint new file mode 100644 index 0000000..9755ab3 --- /dev/null +++ b/.github/.gitlint @@ -0,0 +1,2 @@ +[general] +ignore=B6 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..88d7df4 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Global owner +* @ElBe-Plaq diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..defbeba --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,121 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders 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, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement on +[our discord server](https://discord.gg/JVyyDukQqV). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html), +version 2.0, available at +[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html). + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are available at +[https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..d245223 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,29 @@ +# How to contribute to this project + +Did you find a bug? You want to have a feature implemented? You made code better? +Please follow the instructions below on how to contribute to this project. + +## Notes + +Please do **not** report an issue of pull request if the issue is a security vulnerability. +There is a different way to report such issues. Issues or pull requests about a vulnerability will be removed. + +
+

Report vulnerabilities here

+
+ +## Contributing + +For any issues or proposals, open an issue. If you already wrote your proposed change(s), please open an issue +and a pull request. See below for making changes on your own. + +### Making changes on your own + +1. Create a new issue with a summary of your proposed changes and more. +2. Fork the repository. +3. Implement your changes +4. Test your changes. Run `cargo fmt`, `cargo check` and `cargo clippy` to verify it works. +5. Create a pull request from your fork. +6. If it gets accepted, your changes will be in the next release. + +To everyone who has reported issues, proposed changes or just helped with peoples questions: Thank you! diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..fa8cce5 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +--- +ko_fi: elbeplaq diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..161380c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,33 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG] TITLE" +labels: Bug +assignees: ElBe-Plaq +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + +- OS: [e.g. iOS] +- Rust version [eg. 1.69] +- Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..a61c085 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,6 @@ +--- +blank_issues_enabled: false +contact_links: + - name: Discord Server + url: https://discord.gg/JVyyDukQqV + about: Please ask and answer questions here or just chat with the communtiy. diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 0000000..d45d81d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,7 @@ +--- +name: Documentation +about: Improvements to the documentation. +title: "[DOCUMENTATION] TITLE" +labels: Documentation +assignees: ElBe-Plaq +--- diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md new file mode 100644 index 0000000..54731f2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -0,0 +1,7 @@ +--- +name: Enhancement +about: Improves something already existing. +title: "[ENHANCEMENT] TITLE" +labels: Enhancement +assignees: ElBe-Plaq +--- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..36492b6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[FEATURE] TITLE" +labels: Feature request +assignees: ElBe-Plaq +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..6f9b702 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +# Description + +Summary of all the changes made. + +Closes #(issues that get closed, if this pull request gets closed) + +## Type of change + + + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update +- [ ] Something else + +# Checklist: + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new errors or linter warnings +- [ ] My changes generate no problems with other code +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing tests passed locally with my changes diff --git a/.github/README.md b/.github/README.md new file mode 100644 index 0000000..9bf9fbe --- /dev/null +++ b/.github/README.md @@ -0,0 +1,86 @@ +

+ logging-rs +

+

+ logging-rs helps you add logging to your projects using simple macros. +

+

+ + + + +

+ + + +## About this project + +logging-rs helps you add logging to your projects using simple macros. + +## Installing + +Run the following command to add the package to your dependencies: + +```bash + +$ cargo add logging-rs +... + +``` + +### Git + +To clone the repository locally using git run `git clone https://github.com/ElBe-Development/logging-rs.git`. + +## Usage + +To use logging-rs you need a configuration. It's best to keep it the same across multiple files. You then need to follow these steps: + +1. Import the logging-rs crate: + + ```rust,ignore + use logging_rs; + ``` + +2. Create a new logger object: + + ```rust,ignore + let logger = logging_rs::Logger::new(logging_rs::Formatter::default(), vec![logging_rs::Output::STDOUT]); + ``` + +3. Log the messages you want to log: + + ```rust,ignore + logging_rs::debug!(logger, "Debug message"); + logging_rs::info!(logger, "Info"); + logging_rs::warn!(logger, "Warning"); + logging_rs::error!(logger, "Error!"); + logging_rs::fatal!(logger, "Fatal error!"); + logging_rs::log!(logger, "Log message"); + ``` + +## Example + +With the following rust code: + +```rust,ignore +use logging_rs; + +fn main() { + let logger = logging_rs::Logger::default(); + + logging_rs::debug!(logger, "Debug message"); +} +``` + +You will get the following output: + +```bash +[TIMESTAMP] [DEBUG] src\main.rs: Debug message +``` + +Where `TIMESTAMP` is the current timestamp. + +## Contact + +To contact us, get help or just chat with others, you can visit [our discord server](https://discord.gg/JVyyDukQqV). diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..7466632 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,14 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| -------- | ------------------ | +| `v1.0.0` | :white_check_mark: | + +## Reporting a Vulnerability + +To report a vulnerability, go to [our discord server](https://discord.gg/JVyyDukQqV), write an +[E-Mail](mailto:elbe.dev.plaq@gmail.com) or report it via +[GitHubs security reporting system](https://github.com/ElBe-Development/logging-rs/security/advisories/new) +(preferred). diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 0000000..cde36fa --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,7 @@ +# Support + +You can get support on: + +- [our discord server](https://discord.gg/JVyyDukQqV) +- [GitHub discussions](https://github.com/ElBe-Development/logging-rs/discussions) +- [GitHub issues](https://github.com/ElBe-Development/logging-rs/issues) diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml new file mode 100644 index 0000000..fb03d3c --- /dev/null +++ b/.github/auto_assign.yml @@ -0,0 +1,5 @@ +--- +addReviewers: false +addAssignees: true +assignees: + - ElBe-Plaq diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ea3679d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,33 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +--- +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + assignees: + - "ElBe-Plaq" + labels: + - "dependencies" + + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "daily" + assignees: + - "ElBe-Plaq" + labels: + - "dependencies" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + assignees: + - "ElBe-Plaq" + labels: + - "dependencies" diff --git a/.github/errors.md b/.github/errors.md new file mode 100644 index 0000000..f114728 --- /dev/null +++ b/.github/errors.md @@ -0,0 +1,3 @@ +# errors module + +Module for dealing with errors. diff --git a/.github/example.png b/.github/example.png new file mode 100644 index 0000000..92da719 Binary files /dev/null and b/.github/example.png differ diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..ac92c4e --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,5 @@ +--- +example: + - "examples/*" +dependencies: + - "dev-requirements.txt" diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 0000000..cb54a5e --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,128 @@ +--- +pull_request_rules: + - name: Merge trusted bot updates, no conflicts are present and approved + conditions: + - or: + - "label~=Approved" + - "-#approved-reviews-by=0" + - "-conflict" + - "-draft" + - "-locked" + - "#check-failure=0" + - "author~=.*bot.*" + actions: + comment: + message: | + # Merging pull request + + Checks: + | Name | Status | + |------|--------| + {% for check in check_success %}| {{check}} | :white_check_mark: | + {% endfor %} + merge: + commit_message_template: | + {{title}} + + {{title}} in #{{number}} by @{{author}}, contributing to {{milestone}} + + Changed files: + {% for file in files %}- '{{file}}' + {% endfor %} + + Approved by: @{{ approved_reviews_by | join(', @') }} + + + {% for commit in commits %}Co-authored-by: {{commit.author}} <{{commit.email_author}}> + {% endfor %} + method: merge + delete_head_branch: + - name: Merge if approved, no conflicts are present and it's not a WIP + conditions: + - or: + - "-#approved-reviews-by=0" + - "label~=Approved" + - "label~=Able to merge" + - "-conflict" + - "-draft" + - "-locked" + - "#check-failure=0" + actions: + comment: + message: | + # Merging pull request + + Checks: + | Name | Status | + |------|--------| + {% for check in check_success %}| {{check}} | :white_check_mark: | + {% endfor %} + merge: + commit_message_template: | + {{title}} + + {{title}} in #{{number}} by @{{author}}, contributing to {{milestone}} + + Changed files: + {% for file in files %}- '{{file}}' + {% endfor %} + + Approved by: @{{ approved_reviews_by | join(', @') }} + + + {% for commit in commits %}Co-authored-by: {{commit.author}} <{{commit.email_author}}> + {% endfor %} + method: merge + delete_head_branch: + - name: Add review requested label and request review from ElBe + conditions: + - or: + - "#approved-reviews-by=0" + - "-label~=Approved" + - "-title~=^[WIP].*" + - "-label~=Declined" + - "-label~=Review requested" + - "-draft" + - "-locked" + - "-conflict" + actions: + label: + add: + - Review requested + request_reviews: + users: + - ElBe-Plaq + - name: Warn on conflicts and add label + conditions: + - conflict + actions: + comment: + message: "@{{author}} this pull request has one or more conflicts." + label: + add: + - Invalid + remove: + - Review requested + - name: Remove invalid label if not needed + conditions: + - -conflict + actions: + label: + add: + - Review requested + remove: + - Invalid + - name: Warn on failed checks + conditions: + - "-#check-failure=0" + actions: + comment: + message: | + # Checks failed + + Checks: + | Name | Status | + |------|--------| + {% for check in check_success %}| {{check}} | :white_check_mark: | + {% endfor %}{% for check in check_failure %}| {{check}} | :x: | + {% endfor %} diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..a4d7996 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,11 @@ +--- +daysUntilStale: 60 +daysUntilClose: 7 +exemptLabels: + - Security +staleLabel: stale +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/.github/workflows/codecov_workflow.yml b/.github/workflows/codecov_workflow.yml new file mode 100644 index 0000000..4a813bb --- /dev/null +++ b/.github/workflows/codecov_workflow.yml @@ -0,0 +1,14 @@ +name: Codecov +permissions: read-all + +on: + [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml new file mode 100644 index 0000000..c71a461 --- /dev/null +++ b/.github/workflows/dependencies.yml @@ -0,0 +1,46 @@ +--- +name: Dependencies +permissions: read-all + +on: + push: + paths: ["dev-requirements.txt", "Cargo.toml"] + + pull_request: + paths: ["dev-requirements.txt", "Cargo.toml"] + +jobs: + install-python-dependencies: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies from txt files + run: | + python -m pip install --upgrade pip + pip install -r dev-requirements.txt + install-rust-dependencies: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install dependencies from Cargo.toml + run: cargo update + - name: Install dev-dependencies from Cargo.toml + run: cargo test --no-run + # ^ This is the only way to install dev-dependencies + + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + if: ${{ github.event_name != 'push' }} + - name: Dependency Review + if: ${{ github.event_name != 'push' }} + uses: actions/dependency-review-action@v3 diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml new file mode 100644 index 0000000..34a042d --- /dev/null +++ b/.github/workflows/label.yml @@ -0,0 +1,25 @@ +# This workflow will triage pull requests and apply a label based on the +# paths that are modified in the pull request. +# +# To use this workflow, you will need to set up a .github/labeler.yml +# file with configuration. For more information, see: +# https://github.com/actions/labeler + +--- +name: Labeler +permissions: + pull-requests: write + +on: [pull_request_target] + +jobs: + label: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/megalinter.yml b/.github/workflows/megalinter.yml new file mode 100644 index 0000000..280bede --- /dev/null +++ b/.github/workflows/megalinter.yml @@ -0,0 +1,38 @@ +--- +name: MegaLinter +permissions: read-all + +on: + push: + pull_request: + branches: [main] + +env: + APPLY_FIXES: VALIDATE_ALL_CODEBASE + APPLY_FIXES_EVENT: all + APPLY_FIXES_MODE: commit + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + build: + name: MegaLinter + runs-on: ubuntu-latest + permissions: + contents: write + issues: write + pull-requests: write + steps: + - name: Checkout Code + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} + fetch-depth: 0 + - name: MegaLinter + id: ml + uses: oxsecurity/megalinter@v7 + env: + VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..45c562c --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,18 @@ +name: Rust +permissions: read-all + +on: + [push, pull_request] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6985cf1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/.mega-linter.yml b/.mega-linter.yml new file mode 100644 index 0000000..b10c5b8 --- /dev/null +++ b/.mega-linter.yml @@ -0,0 +1,16 @@ +--- +DISABLE_ERRORS_LINTERS: + - SPELL_CSPELL + - REPOSITORY_DEVSKIM # cspell:disable-line + - MAKEFILE_CHECKMAKE # cspell:disable-line + - HTML_HTMLHINT # cspell:disable-line + - MARKDOWN_MARKDOWN_LINK_CHECK + - REPOSITORY_DUSTILOCK # cspell:disable-line + - JAVASCRIPT_STANDARD + - REPOSITORY_TRUFFLEHOG # cspell:disable-line + - SPELL_LYCHEE +FILTER_REGEX_EXCLUDE: .*mypy.* # cspell:disable-line +EDITORCONFIG_EDITORCONFIG_CHECKER_FILTER_REGEX_EXCLUDE: "Docs/acknowledgements.md|src/Installer/Linux/installer.bash" +REPORT_OUTPUT_FOLDER: none +SHOW_ELAPSED_TIME: true +VALIDATE_ALL_CODEBASE: false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..6c07b01 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,38 @@ +--- +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-added-large-files + - id: check-executables-have-shebangs + - id: check-json + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-toml + - id: check-yaml + - id: pretty-format-json + args: [--autofix] + - id: requirements-txt-fixer + - id: trailing-whitespace + - repo: https://github.com/jorisroovers/gitlint + rev: v0.19.1 + hooks: + - id: gitlint + args: [--config=.github\.gitlint, --msg-filename] + - repo: https://github.com/doublify/pre-commit-rust + rev: v1.0 + hooks: + - id: fmt + - id: cargo-check + - repo: local + hooks: + - id: clippy + name: Run clippy linter + entry: cargo clippy -- -A non_snake_case + language: system + pass_filenames: false +ci: + skip: + - fmt + - cargo-check + - clippy diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..51ffa65 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "logging-rs" +description = "logging-rs helps you add logging to your projects using simple macros." +version = "1.0.0" +authors = [ + "ElBe-Plaq " +] +edition = "2021" +rust-version = "1.69" +documentation = "https://docs.rs/logging_rs/" +readme = ".github/README.md" +repository = "https://github.com/ElBe-Development/logging-rs/" +license = "MIT" +keywords = ["log", "logger", "logging", "debug", "debugging"] +categories = [ + "development-tools::debugging", +] +publish = true + +[dependencies] +# chrono = "0.4.31" diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..04e1350 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 ElBe Development + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..b2a0e98 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,10 @@ +coverage: + status: + project: + default: + target: 50% + threshold: 1% + +comment: + require_changes: true + require_ci_to_pass: false diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..56ce91b --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1 @@ +pre-commit==3.4.0; python_version>='3.8' diff --git a/examples/main.rs b/examples/main.rs new file mode 100644 index 0000000..cc5cb60 --- /dev/null +++ b/examples/main.rs @@ -0,0 +1,12 @@ +use logging_rs; + +fn main() { + let logger = logging_rs::Logger::default(); + + logging_rs::debug!(logger, "Debug message"); + logging_rs::info!(logger, "Info"); + logging_rs::warn!(logger, "Warning"); + logging_rs::error!(logger, "Error!"); + logging_rs::fatal!(logger, "Fatal error!"); + logging_rs::log!(logger, "Log message"); +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..a6550c9 --- /dev/null +++ b/justfile @@ -0,0 +1,25 @@ +alias b := build +alias c := clean +alias l := lint +alias r := run +alias t := test + +# Compiles the rust source files +build *ARGUMENTS: + cargo build --release *ARGUMENTS + +# Removes temporary files +clean: + cargo clean + +# Lints the rust source files +lint *ARGUMENTS: + cargo check *ARGUMENTS + +# Compiles and executes the main.rs file +run *ARGUMENTS: + cargo run *ARGUMENTS + +# Runs the unittests +test *ARGUMENTS: + cargo test *ARGUMENTS diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..3a6ef8d --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,159 @@ +#![doc = include_str!("../.github/errors.md")] +// logging-rs errors +// Version: 1.0.0 + +// Copyright (c) 2023-present ElBe Development. + +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the 'Software'), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +//////////////////////////////// +// IMPORTS AND USE STATEMENTS // +//////////////////////////////// + +use std::fmt; + + +/////////// +// ERROR // +/////////// + +/// Error object. +/// +/// Use [`Error::new()`] to create error objects instead of using this struct. +/// +/// # Parameters +/// +/// - `name`: The errors name. +/// - `description`: The error description. +/// - `exit_code`: The errors exit code. +/// +/// # Returns +/// +/// A new `Error` object with the specified name and description. +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// logging_rs::errors::Error { +/// name: "name".to_owned(), +/// description: "description".to_owned(), +/// exit_code: 1 +/// }; +/// ``` +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Error { + /// The errors name. + pub name: String, + /// The error description. + pub description: String, + /// The errors exit code. + pub exit_code: i32, +} + +/// Display implementation for the error object. +impl fmt::Display for Error { + /// Format implementation for the error object. + /// + /// # Parameters + /// + /// - `self`: The error object. + /// - `f`: The [`fmt::Formatter`] to use. + /// + /// # Returns + /// + /// A [`fmt::Result`] containing the formatted error message. + /// + /// # Examples + /// + /// ```rust + /// # use logging_rs; + /// # let error = logging_rs::errors::Error::new("name", "description", 1); + /// println!("{}", error); + /// ``` + /// + /// # See also + /// + /// - [`fmt::Display`] + /// - [`Error`] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\x1b[31;1m{}\x1b[0m: {}", self.name, self.description) + } +} + +impl Error { + /// Creates a new error object. + /// + /// # Parameters + /// + /// - `name`: The errors name. + /// - `description`: The error description. + /// - `exit_code`: The errors exit code. + /// + /// # Returns + /// + /// A new `Error` object with the specified name and description. + /// + /// # Examples + /// + /// ```rust + /// # use logging_rs; + /// logging_rs::errors::Error::new("name", "description", 1); + /// ``` + /// + /// # See also + /// + /// - [`Error`] + pub fn new(name: &str, description: &str, exit_code: i32) -> Error { + return Error { + name: name.to_owned(), + description: description.to_owned(), + exit_code: exit_code, + }; + } + + /// Raises the error and exits with the specified exit code. + /// + /// # Parameters + /// + /// - `self`: The error object. + /// - `details`: The error details. + /// + /// # Aborts + /// + /// Exits with the specified exit code. + /// + /// # Examples + /// + /// ```should_panic + /// # use logging_rs; + /// # let error: logging_rs::errors::Error = logging_rs::errors::Error::new("name", "description", 1); + /// error.raise("Something went very wrong"); + /// ``` + /// + /// # See also + /// + /// - [`Error`] + pub fn raise(&self, details: &str) { + eprintln!("{}", self); + eprintln!("{}", details); + + std::process::exit(self.exit_code); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ad6dcd0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,657 @@ +#![doc = include_str!("../.github/README.md")] +// Logging-rs. +// Version: 1.0.0 + +// Copyright (c) 2023-present I Language Development. + +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the 'Software'), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +///////////// +// EXPORTS // +///////////// + +pub mod errors; + + +///////////// +// IMPORTS // +///////////// + +use std; +use std::io::Write; + +// use chrono; + + +//////////////// +// LOG LEVELS // +//////////////// + +/// Log levels +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum Level { + /// Debug log level. The default value + #[default] + DEBUG, + /// Info log level + INFO, + /// Warn log level + WARN, + /// Error log level + ERROR, + /// Fatal log level + FATAL, + /// Message log level + MESSAGE +} + + +////////////////// +// HTTP METHODS // +////////////////// + +// HTTP methods +/*#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum HTTPMethod { + /// GET request. The default value + #[default] + GET, + /// POST request + POST, + /// PUT request + PUT, + /// PATCH request + PATCH +}*/ + + +///////////////// +// OUTPUT TYPE // +///////////////// + +/// Output types +#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum Output { + /// Stdout. The default value + #[default] + STDOUT, + /// Stderr + STDERR, + /// File + FILE { + /// File path + path: String + }, + // Web request (not currently implemented) + /*REQUEST { + method: HTTPMethod, + url: String + }*/ +} + + +/////////////// +// FORMATTER // +/////////////// + +/// Logging formatter object. +/// +/// Use [`Formatter::new()`] to create formatter objects instead of using this struct. +/// +/// # Parameters +/// +/// - `color_format_string`: Format string supporting special ASCII control characters +/// - `format_string`: Format string *NOT* supporting special ASCII control characters +/// - `timestamp_format`: Timestamp format string in strftime format +/// +/// # Returns +/// +/// A new `Formatter` object with the specified format strings. +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// logging_rs::Formatter { +/// color_format_string: "format string with color support".to_owned(), +/// format_string: "format string".to_owned(), +/// timestamp_format: "timestamp format".to_owned() +/// }; +/// ``` +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Formatter { + /// Format string supporting special ASCII control characters + pub color_format_string: String, + /// Format string *NOT* supporting special ASCII control characters + pub format_string: String, + /// Timestamp format string in strftime format + pub timestamp_format: String, +} + +impl Default for Formatter { + fn default() -> Formatter { + return Formatter::new("[{{color.bright_blue}}{{timestamp}}{{end}}] [{{level}}] {{path}}: {{message}}", "[{{timestamp}}] [{{level}}] {{path}}: {{message}}", "%Y-%m-%d %H:%M:%S"); + } +} + +impl Formatter { + /// Creates a new formatter object. + /// + /// # Parameters + /// + /// - `color_format_string`: Format string supporting special ASCII control characters + /// - `format_string`: Format string *NOT* supporting special ASCII control characters + /// - `timestamp_format`: Timestamp format string in strftime format + /// + /// # Returns + /// + /// A new `Formatter` object with the specified format strings. + /// + /// # Examples + /// + /// ```rust + /// # use logging_rs; + /// logging_rs::Formatter::new( + /// "[{{color.bright_blue}}{{timestamp}}{{end}}] [{{level}}] {{path}}: {{message}}", + /// "[{{timestamp}}] [{{level}}] {{path}}: {{message}}", + /// "%Y-%m-%d %H:%M:%S" + /// ); + /// ``` + /// + /// # See also + /// + /// - [`Formatter`] + pub fn new(color_format_string: &str, format_string: &str, timestamp_format: &str) -> Formatter { + Formatter { + color_format_string: color_format_string.to_owned(), + format_string: format_string.to_owned(), + timestamp_format: timestamp_format.to_owned() + } + } + + /// Formats the given message. + /// + /// # Parameters + /// + /// - `self`: The formatter object + /// - `output`: The [`Output`] to write to + /// - `level`: The log [`Level`] to use for formatting + /// - `message`: The message to log + /// - `arguments`: A vector of additional formatting arguments + /// + /// # Returns + /// + /// A `String` containing the formatted message. + /// + /// # Examples + /// + /// ```rust + /// # use logging_rs; + /// # let formatter: logging_rs::Formatter = logging_rs::Formatter::default(); + /// formatter.format( + /// logging_rs::Output::default(), + /// logging_rs::Level::default(), + /// "Some message with an {{argument}}", + /// vec![("argument", "replaced value")] + /// ); + /// ``` + /// + /// # See also + /// + /// - [`Formatter`] + /// - [`Output`] + /// - [`Level`] + pub fn format<'a>(&self, output: Output, level: Level, message: &'a str, mut arguments: Vec<(&str, &'a str)>) -> String { + // TODO (ElBe): Make timestamps work. None of chrono, time or humantime have the things I want + let timestamp: &str = "TIMESTAMP"; + + // let time = chrono::Utc::now(); + //let _timestamp = time.format("%Y-%m-%d %H:%M:%S").to_string(); //chrono::format::DelayedFormat> + //let parsed = chrono::NaiveDateTime::parse_from_str(&_timestamp.to_string(), "%Y-%m-%d %H:%M:%S").expect("Bad"); + + //let borrowed = &_timestamp; + + //println!("{}", _timestamp); + //println!("{}", parsed.to_string().as_str()); + + // arguments.push(("timestamp", &time.format("%Y-%m-%d %H:%M:%S").to_string())); + + let mut colors: Vec<(&str, &str)> = vec![ + // Formatting codes + ("end", "\x1b[0m"), + ("bold", "\x1b[1m"), + ("italic", "\x1b[3m"), + ("underline", "\x1b[4m"), + ("overline", "\x1b[53m"), + + // Foreground colors + ("color.black", "\x1b[30m"), + ("color.red", "\x1b[31m"), + ("color.green", "\x1b[32m"), + ("color.yellow", "\x1b[33m"), + ("color.blue", "\x1b[34m"), + ("color.magenta", "\x1b[35m"), + ("color.cyan", "\x1b[36m"), + ("color.white", "\x1b[37m"), + + // Bright foreground colors + ("color.bright_black", "\x1b[90m"), + ("color.bright_red", "\x1b[91m"), + ("color.bright_green", "\x1b[92m"), + ("color.bright_yellow", "\x1b[93m"), + ("color.bright_blue", "\x1b[94m"), + ("color.bright_magenta", "\x1b[95m"), + ("color.bright_cyan", "\x1b[96m"), + ("color.bright_white", "\x1b[97m"), + + // Background colors + ("back.black", "\x1b[40m"), + ("back.red", "\x1b[41m"), + ("back.green", "\x1b[42m"), + ("back.yellow", "\x1b[43m"), + ("back.blue", "\x1b[44m"), + ("back.magenta", "\x1b[45m"), + ("back.cyan", "\x1b[46m"), + ("back.white", "\x1b[47m"), + + // Bright background colors + ("back.bright_black", "\x1b[100m"), + ("back.bright_red", "\x1b[101m"), + ("back.bright_green", "\x1b[102m"), + ("back.bright_yellow", "\x1b[103m"), + ("back.bright_blue", "\x1b[104m"), + ("back.bright_magenta", "\x1b[105m"), + ("back.bright_cyan", "\x1b[106m"), + ("back.bright_white", "\x1b[107m"), + ]; + + let level_string: (&str, &str) = ("level", match level { + Level::DEBUG => "DEBUG", + Level::INFO => "INFO", + Level::WARN => "WARNING", + Level::ERROR => "ERROR", + Level::FATAL => "FATAL", + Level::MESSAGE => "MESSAGE" + }); + let colored_level_string: (&str, &str) = ("level", match level { + Level::DEBUG => "DEBUG", + Level::INFO => "{{color.blue}}INFO{{end}}", + Level::WARN => "{{color.yellow}}WARNING{{end}}", + Level::ERROR => "{{color.red}}ERROR{{end}}", + Level::FATAL => "{{color.red}}FATAL{{end}}", + Level::MESSAGE => "{{color.blue}}MESSAGE{{end}}" + }); + + arguments.push(("message", message)); + arguments.push(("timestamp", timestamp)); + //arguments.push(("timestamp", chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string().to_owned().as_str())); + + let mut result: String = match output { + Output::STDOUT | Output::STDERR => { + arguments.push(colored_level_string); + self.color_format_string.to_owned() + }, + _ => { + arguments.push(level_string); + self.format_string.to_owned() + } + }; + + arguments.append(&mut colors); + + for (key, value) in arguments { + result = result.replace(("{{".to_owned() + key + "}}").as_str(), value); + } + + return result.clone(); + } +} + + +/////////////////// +// LOGGER STRUCT // +/////////////////// + +/// Logger object. +/// +/// Use [`Logger::new()`] to create logger objects instead of using this struct. +/// +/// # Parameters +/// +/// - `formatter`: The [`Formatter`] to use for formatting messages +/// - `writable_list`: A vector of [`Output`]s to write to +/// +/// # Returns +/// +/// A new `Logger` object with the specified formatter and writables. +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// logging_rs::Logger { +/// formatter: logging_rs::Formatter::default(), +/// writable_list: vec![logging_rs::Output::default()] +/// }; +/// ``` +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Logger { + pub formatter: Formatter, + pub writable_list: Vec +} + +impl Default for Logger { + fn default() -> Logger { + return Logger::new(Formatter::default(), vec![Output::STDOUT]); + } +} + +impl Logger { + /// Creates a new logger object. + /// + /// # Parameters + /// + /// - `formatter`: The [`Formatter`] to use for formatting messages + /// - `writable_list`: A vector of [`Output`]s to write to + /// + /// # Returns + /// + /// A new `Logger` object with the specified formatter and writables. + /// + /// # Examples + /// + /// ```rust + /// # use logging_rs; + /// logging_rs::Logger::new(logging_rs::Formatter::default(), vec![logging_rs::Output::default()]); + /// ``` + /// + /// # See also + /// + /// - [`Logger`] + pub fn new(formatter: Formatter, writable_list: Vec) -> Logger { + Logger { + formatter: formatter, + writable_list: writable_list + } + } + + /// Logs the given message. + /// + /// # Parameters + /// + /// - `self`: The logger object + /// - `message`: The message to log + /// - `level`: The log [`Level`] to use for logging + /// - `path`: The path of the calling file + /// + /// # Returns + /// + /// A `String` containing the formatted message. + /// + /// # Examples + /// + /// ```rust + /// # use logging_rs; + /// # let logger: logging_rs::Logger = logging_rs::Logger::default(); + /// logger.log( + /// "Some message", + /// logging_rs::Level::default(), + /// "src/lib.rs" + /// ); + /// ``` + /// + /// # See also + /// + /// - [`debug!()`] + /// - [`info!()`] + /// - [`warn!()`] + /// - [`error!()`] + /// - [`fatal!()`] + /// - [`log!()`] + /// - [`Logger`] + /// - [`Level`] + pub fn log(&self, message: &str, level: Level, path: &str) { + for writable in self.writable_list.clone() { + let formatted: String = self.formatter.format(writable.clone(), level, message, vec![("path", path)]); + + match writable { + Output::STDOUT => println!("{}", formatted), + Output::STDERR => eprintln!("{}", formatted), + Output::FILE { ref path } => { + let file: Result = std::fs::OpenOptions::new().create(true).append(true).write(true).open(path); + let write: Result<_, std::io::Error> = write!(file.as_ref().unwrap(), "{}", formatted); + + if let Err(error) = file { + errors::Error::new("File error", "The file could not be opened", 1).raise(format!("Path: {}\nError: {}", path, error).as_str()); + } + + if let Err(error) = write { + errors::Error::new("Writing error", "The file could not be edited", 2).raise(format!("File: {}\nText: {}\nError: {}", path, formatted, error).as_str()); + } + }, + // TODO (ElBe): Add HTTP support + /*Output::REQUEST { ref method, ref url } => { + match method { + HTTPMethod::GET => {}, + HTTPMethod::POST => {}, + HTTPMethod::PUT => {}, + HTTPMethod::PATCH => {}, + } + }*/ + } + } + } +} + + +//////////// +// MACROS // +//////////// + +/// Logs the given message with logging level [`Level::DEBUG`]. +/// +/// # Parameters +/// +/// - `logger`: The logger object to log with +/// - `message`: The message to log +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// # let logger: logging_rs::Logger = logging_rs::Logger::default(); +/// logging_rs::debug!(logger, "A message"); +/// ``` +/// +/// # See also +/// +/// - [`info!()`] +/// - [`warn!()`] +/// - [`error!()`] +/// - [`fatal!()`] +/// - [`log!()`] +/// - [`Logger`] +#[macro_export] +macro_rules! debug { + ($logger:expr, $message:expr) => { + { + $logger.log($message, $crate::Level::DEBUG, std::panic::Location::caller().file()); + } + }; +} + +/// Logs the given message with logging level [`Level::INFO`]. +/// +/// # Parameters +/// +/// - `logger`: The logger object to log with +/// - `message`: The message to log +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// # let logger: logging_rs::Logger = logging_rs::Logger::default(); +/// logging_rs::info!(logger, "A message"); +/// ``` +/// +/// # See also +/// +/// - [`debug!()`] +/// - [`warn!()`] +/// - [`error!()`] +/// - [`fatal!()`] +/// - [`log!()`] +/// - [`Logger`] +#[macro_export] +macro_rules! info { + ($logger:expr, $message:expr) => { + { + $logger.log($message, $crate::Level::INFO, std::panic::Location::caller().file()); + } + }; +} + +/// Logs the given message with logging level [`Level::WARN`]. +/// +/// # Parameters +/// +/// - `logger`: The logger object to log with +/// - `message`: The message to log +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// # let logger: logging_rs::Logger = logging_rs::Logger::default(); +/// logging_rs::warn!(logger, "A message"); +/// ``` +/// +/// # See also +/// +/// - [`debug!()`] +/// - [`info!()`] +/// - [`error!()`] +/// - [`fatal!()`] +/// - [`log!()`] +/// - [`Logger`] +#[macro_export] +macro_rules! warn { + ($logger:expr, $message:expr) => { + { + $logger.log($message, $crate::Level::WARN, std::panic::Location::caller().file()); + } + }; +} + +/// Logs the given message with logging level [`Level::ERROR`]. +/// +/// # Parameters +/// +/// - `logger`: The logger object to log with +/// - `message`: The message to log +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// # let logger: logging_rs::Logger = logging_rs::Logger::default(); +/// logging_rs::error!(logger, "A message"); +/// ``` +/// +/// # See also +/// +/// - [`debug!()`] +/// - [`info!()`] +/// - [`warn!()`] +/// - [`fatal!()`] +/// - [`log!()`] +/// - [`Logger`] +#[macro_export] +macro_rules! error { + ($logger:expr, $message:expr) => { + { + $logger.log($message, $crate::Level::ERROR, std::panic::Location::caller().file()); + } + }; +} + +/// Logs the given message with logging level [`Level::FATAL`]. +/// +/// # Parameters +/// +/// - `logger`: The logger object to log with +/// - `message`: The message to log +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// # let logger: logging_rs::Logger = logging_rs::Logger::default(); +/// logging_rs::fatal!(logger, "A message"); +/// ``` +/// +/// # See also +/// +/// - [`debug!()`] +/// - [`info!()`] +/// - [`warn!()`] +/// - [`error!()`] +/// - [`log!()`] +/// - [`Logger`] +#[macro_export] +macro_rules! fatal { + ($logger:expr, $message:expr) => { + { + $logger.log($message, $crate::Level::FATAL, std::panic::Location::caller().file()); + } + }; +} + +/// Logs the given message with logging level [`Level::MESSAGE`]. +/// +/// # Parameters +/// +/// - `logger`: The logger object to log with +/// - `message`: The message to log +/// +/// # Examples +/// +/// ```rust +/// # use logging_rs; +/// # let logger: logging_rs::Logger = logging_rs::Logger::default(); +/// logging_rs::log!(logger, "A message"); +/// ``` +/// +/// # See also +/// +/// - [`debug!()`] +/// - [`info!()`] +/// - [`warn!()`] +/// - [`error!()`] +/// - [`fatal!()`] +/// - [`Logger`] +#[macro_export] +macro_rules! log { + ($logger:expr, $message:expr) => { + { + $logger.log($message, $crate::Level::MESSAGE, std::panic::Location::caller().file()); + } + }; +} diff --git a/tests/errors.rs b/tests/errors.rs new file mode 100644 index 0000000..37b9b6e --- /dev/null +++ b/tests/errors.rs @@ -0,0 +1,72 @@ +// logging-rs error tests +// Version: 1.0.0 + +// Copyright (c) 2023-present ElBe Development. + +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the 'Software'), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +//////////////////////////////// +// IMPORTS AND USE STATEMENTS // +//////////////////////////////// + +#[allow(unused_imports)] +use logging_rs; + + +/////////// +// TESTS // +/////////// + +#[cfg(test)] +mod tests { + #[test] + fn test_error() { + let error: logging_rs::errors::Error = + logging_rs::errors::Error::new("name", "description", 1); + + assert_eq!( + error, + logging_rs::errors::Error { + name: "name".to_owned(), + description: "description".to_owned(), + exit_code: 1 + } + ); + } + + #[test] + #[ignore] + fn raise_helper() { + let error: logging_rs::errors::Error = + logging_rs::errors::Error::new("name", "description", 1); + error.raise("details"); + } + + #[test] + fn test_raise() { + let status = std::process::Command::new("cargo") + .args(&["test", "--", "--ignored"]) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .status() + .expect("Unable to run program"); + + assert_eq!(Some(1), status.code()) + } +} diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 0000000..e8ea04c --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,113 @@ +// logging-rs tests +// Version: 1.0.0 + +// Copyright (c) 2023-present ElBe Development. + +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the 'Software'), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +//////////////////////////////// +// IMPORTS AND USE STATEMENTS // +//////////////////////////////// + +#[allow(unused_imports)] +use logging_rs; + + +/////////// +// TESTS // +/////////// + +#[cfg(test)] +mod tests { + #[test] + fn test_level_default() { + assert_eq!( + logging_rs::Level::default(), + logging_rs::Level::DEBUG + ); + } + + #[test] + fn test_output_default() { + assert_eq!( + logging_rs::Output::default(), + logging_rs::Output::STDOUT + ); + } + + #[test] + fn test_formatter_default() { + assert_eq!( + logging_rs::Formatter::default(), + logging_rs::Formatter { + color_format_string: "[{{color.bright_blue}}{{timestamp}}{{end}}] [{{level}}] {{path}}: {{message}}".to_owned(), + format_string: "[{{timestamp}}] [{{level}}] {{path}}: {{message}}".to_owned(), + timestamp_format: "%Y-%m-%d %H:%M:%S".to_owned() + } + ); + } + + #[test] + fn test_formatter_new() { + assert_eq!( + logging_rs::Formatter::new( + "[{{color.bright_blue}}{{timestamp}}{{end}}] [{{level}}] {{path}}: {{message}}", + "[{{timestamp}}] [{{level}}] {{path}}: {{message}}", + "%Y-%m-%d %H:%M:%S" + ), + logging_rs::Formatter { + color_format_string: "[{{color.bright_blue}}{{timestamp}}{{end}}] [{{level}}] {{path}}: {{message}}".to_owned(), + format_string: "[{{timestamp}}] [{{level}}] {{path}}: {{message}}".to_owned(), + timestamp_format: "%Y-%m-%d %H:%M:%S".to_owned() + } + ); + } + + #[test] + fn test_formatter_format() { + let formatter: logging_rs::Formatter = logging_rs::Formatter::default(); + + assert_eq!( + formatter.format(logging_rs::Output::default(), logging_rs::Level::default(), "Test", vec![]), + "[\x1b[94mTIMESTAMP\x1b[0m] [DEBUG] {{path}}: Test" + ); + } + + #[test] + fn test_logger_default() { + assert_eq!( + logging_rs::Logger::default(), + logging_rs::Logger { + formatter: logging_rs::Formatter::default(), + writable_list: vec![logging_rs::Output::STDOUT] + } + ); + } + + #[test] + fn test_logger_new() { + assert_eq!( + logging_rs::Logger::new(logging_rs::Formatter::default(), vec![logging_rs::Output::STDOUT]), + logging_rs::Logger { + formatter: logging_rs::Formatter::default(), + writable_list: vec![logging_rs::Output::STDOUT] + } + ); + } +}