diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..c3421a1 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +.goassets diff --git a/.github/assert-contributors.sh b/.github/assert-contributors.sh deleted file mode 100644 index b3baa57..0000000 --- a/.github/assert-contributors.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -set -e - -# Unshallow the repo, this check doesn't work with this enabled -# https://github.com/travis-ci/travis-ci/issues/3412 -if [ -f $(git rev-parse --git-dir)/shallow ]; then - git fetch --unshallow || true -fi - -SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) - -CONTRIBUTORS=() -EXCLUDED_CONTIBUTORS=('John R. Bradley') -MISSING_CONTIBUTORS=() - -shouldBeIncluded () { - for i in "${EXCLUDED_CONTIBUTORS[@]}" - do - if [ "$i" == "$1" ] ; then - return 1 - fi - done - return 0 -} - - -IFS=$'\n' #Only split on newline -for contributor in $(git log --format='%aN' | sort -u) -do - if shouldBeIncluded $contributor; then - if ! grep -q "$contributor" "$SCRIPT_PATH/../README.md"; then - MISSING_CONTIBUTORS+=("$contributor") - fi - fi -done -unset IFS - -if [ ${#MISSING_CONTIBUTORS[@]} -ne 0 ]; then - echo "Please add the following contributors to the README" - for i in "${MISSING_CONTIBUTORS[@]}" - do - echo "$i" - done - exit 1 -fi diff --git a/.github/fetch-scripts.sh b/.github/fetch-scripts.sh new file mode 100755 index 0000000..f333841 --- /dev/null +++ b/.github/fetch-scripts.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +set -eu + +SCRIPT_PATH="$(realpath "$(dirname "$0")")" +GOASSETS_PATH="${SCRIPT_PATH}/.goassets" + +GOASSETS_REF=${GOASSETS_REF:-master} + +if [ -d "${GOASSETS_PATH}" ]; then + if ! git -C "${GOASSETS_PATH}" diff --exit-code; then + echo "${GOASSETS_PATH} has uncommitted changes" >&2 + exit 1 + fi + git -C "${GOASSETS_PATH}" fetch origin + git -C "${GOASSETS_PATH}" checkout ${GOASSETS_REF} + git -C "${GOASSETS_PATH}" reset --hard origin/${GOASSETS_REF} +else + git clone -b ${GOASSETS_REF} https://github.com/pion/.goassets.git "${GOASSETS_PATH}" +fi diff --git a/.github/install-hooks.sh b/.github/install-hooks.sh new file mode 100755 index 0000000..8aa34be --- /dev/null +++ b/.github/install-hooks.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +SCRIPT_PATH="$(realpath "$(dirname "$0")")" + +. ${SCRIPT_PATH}/fetch-scripts.sh + +cp "${GOASSETS_PATH}/hooks/commit-msg.sh" "${SCRIPT_PATH}/../.git/hooks/commit-msg" +cp "${GOASSETS_PATH}/hooks/pre-commit.sh" "${SCRIPT_PATH}/../.git/hooks/pre-commit" +cp "${GOASSETS_PATH}/hooks/pre-push.sh" "${SCRIPT_PATH}/../.git/hooks/pre-push" diff --git a/.github/lint-commit-message.sh b/.github/lint-commit-message.sh deleted file mode 100644 index df2ea30..0000000 --- a/.github/lint-commit-message.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -set -e - -display_commit_message_error() { -cat << EndOfMessage -$1 - -------------------------------------------------- -The preceding commit message is invalid -it failed '$2' of the following checks - -* Separate subject from body with a blank line -* Limit the subject line to 50 characters -* Capitalize the subject line -* Do not end the subject line with a period -* Wrap the body at 72 characters -EndOfMessage - - exit 1 -} - -lint_commit_message() { - if [[ "$(echo "$1" | awk 'NR == 2 {print $1;}' | wc -c)" -ne 1 ]]; then - display_commit_message_error "$1" 'Separate subject from body with a blank line' - fi - - if [[ "$(echo "$1" | head -n1 | wc -m)" -gt 50 ]]; then - display_commit_message_error "$1" 'Limit the subject line to 50 characters' - fi - - if [[ ! $1 =~ ^[A-Z] ]]; then - display_commit_message_error "$1" 'Capitalize the subject line' - fi - - if [[ "$(echo "$1" | awk 'NR == 1 {print substr($0,length($0),1)}')" == "." ]]; then - display_commit_message_error "$1" 'Do not end the subject line with a period' - fi - - if [[ "$(echo "$1" | awk '{print length}' | sort -nr | head -1)" -gt 72 ]]; then - display_commit_message_error "$1" 'Wrap the body at 72 characters' - fi -} - -if [ "$#" -eq 1 ]; then - if [ ! -f "$1" ]; then - echo "$0 was passed one argument, but was not a valid file" - exit 1 - fi - lint_commit_message "$(sed -n '/# Please enter the commit message for your changes. Lines starting/q;p' "$1")" -else - # TRAVIS_COMMIT_RANGE is empty for initial branch commit - if [[ "${TRAVIS_COMMIT_RANGE}" != *"..."* ]]; then - parent=$(git log -n 1 --format="%P" ${TRAVIS_COMMIT_RANGE}) - TRAVIS_COMMIT_RANGE="${TRAVIS_COMMIT_RANGE}...$parent" - fi - - for commit in $(git rev-list ${TRAVIS_COMMIT_RANGE}); do - lint_commit_message "$(git log --format="%B" -n 1 $commit)" - done -fi diff --git a/.github/lint-disallowed-functions-in-library.sh b/.github/lint-disallowed-functions-in-library.sh deleted file mode 100644 index f316c18..0000000 --- a/.github/lint-disallowed-functions-in-library.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -set -e - -# Disallow usages of functions that cause the program to exit in the library code -SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) -EXCLUDE_DIRECTORIES="--exclude-dir=examples --exclude-dir=.git --exclude-dir=.github " -DISALLOWED_FUNCTIONS=('os.Exit(' 'panic(' 'Fatal(' 'Fatalf(' 'Fatalln(') - - -for disallowedFunction in "${DISALLOWED_FUNCTIONS[@]}" -do - if grep -R $EXCLUDE_DIRECTORIES -e "$disallowedFunction" "$SCRIPT_PATH/.." | grep -v -e '_test.go' -e 'nolint'; then - echo "$disallowedFunction may only be used in example code" - exit 1 - fi -done diff --git a/.github/workflows/api.yaml b/.github/workflows/api.yaml new file mode 100644 index 0000000..1032179 --- /dev/null +++ b/.github/workflows/api.yaml @@ -0,0 +1,20 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# If this repository should have package specific CI config, +# remove the repository name from .goassets/.github/workflows/assets-sync.yml. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +name: API +on: + pull_request: + +jobs: + check: + uses: pion/.goassets/.github/workflows/api.reusable.yml@master diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..ea9b825 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,28 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# If this repository should have package specific CI config, +# remove the repository name from .goassets/.github/workflows/assets-sync.yml. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +name: CodeQL + +on: + workflow_dispatch: + schedule: + - cron: '23 5 * * 0' + pull_request: + branches: + - master + paths: + - '**.go' + +jobs: + analyze: + uses: pion/.goassets/.github/workflows/codeql-analysis.reusable.yml@master diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..5dd3a99 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,20 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# If this repository should have package specific CI config, +# remove the repository name from .goassets/.github/workflows/assets-sync.yml. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +name: Lint +on: + pull_request: + +jobs: + lint: + uses: pion/.goassets/.github/workflows/lint.reusable.yml@master diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b4967b2 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,24 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# If this repository should have package specific CI config, +# remove the repository name from .goassets/.github/workflows/assets-sync.yml. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +name: Release +on: + push: + tags: + - 'v*' + +jobs: + release: + uses: pion/.goassets/.github/workflows/release.reusable.yml@master + with: + go-version: "1.24" # auto-update/latest-go-version diff --git a/.github/workflows/renovate-go-sum-fix.yaml b/.github/workflows/renovate-go-sum-fix.yaml new file mode 100644 index 0000000..b7bb1b4 --- /dev/null +++ b/.github/workflows/renovate-go-sum-fix.yaml @@ -0,0 +1,24 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# If this repository should have package specific CI config, +# remove the repository name from .goassets/.github/workflows/assets-sync.yml. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +name: Fix go.sum +on: + push: + branches: + - renovate/* + +jobs: + fix: + uses: pion/.goassets/.github/workflows/renovate-go-sum-fix.reusable.yml@master + secrets: + token: ${{ secrets.PIONBOT_PRIVATE_KEY }} diff --git a/.github/workflows/reuse.yml b/.github/workflows/reuse.yml new file mode 100644 index 0000000..8633a12 --- /dev/null +++ b/.github/workflows/reuse.yml @@ -0,0 +1,22 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# If this repository should have package specific CI config, +# remove the repository name from .goassets/.github/workflows/assets-sync.yml. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +name: REUSE Compliance Check + +on: + push: + pull_request: + +jobs: + lint: + uses: pion/.goassets/.github/workflows/reuse.reusable.yml@master diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..7713e93 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,45 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# If this repository should have package specific CI config, +# remove the repository name from .goassets/.github/workflows/assets-sync.yml. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +name: Test +on: + push: + branches: + - master + pull_request: + +jobs: + test: + uses: pion/.goassets/.github/workflows/test.reusable.yml@master + strategy: + matrix: + go: ["1.24", "1.23"] # auto-update/supported-go-version-list + fail-fast: false + with: + go-version: ${{ matrix.go }} + secrets: inherit + + test-i386: + uses: pion/.goassets/.github/workflows/test-i386.reusable.yml@master + strategy: + matrix: + go: ["1.24", "1.23"] # auto-update/supported-go-version-list + fail-fast: false + with: + go-version: ${{ matrix.go }} + + test-wasm: + uses: pion/.goassets/.github/workflows/test-wasm.reusable.yml@master + with: + go-version: "1.24" # auto-update/latest-go-version + secrets: inherit diff --git a/.github/workflows/tidy-check.yaml b/.github/workflows/tidy-check.yaml new file mode 100644 index 0000000..710dbc9 --- /dev/null +++ b/.github/workflows/tidy-check.yaml @@ -0,0 +1,25 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# If this repository should have package specific CI config, +# remove the repository name from .goassets/.github/workflows/assets-sync.yml. +# +# If you want to update the shared CI config, send a PR to +# https://github.com/pion/.goassets instead of this repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +name: Go mod tidy +on: + pull_request: + push: + branches: + - master + +jobs: + tidy: + uses: pion/.goassets/.github/workflows/tidy-check.reusable.yml@master + with: + go-version: "1.24" # auto-update/latest-go-version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e2f206 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +### JetBrains IDE ### +##################### +.idea/ + +### Emacs Temporary Files ### +############################# +*~ + +### Folders ### +############### +bin/ +vendor/ +node_modules/ + +### Files ### +############# +*.ivf +*.ogg +tags +cover.out +*.sw[poe] +*.wasm +examples/sfu-ws/cert.pem +examples/sfu-ws/key.pem +wasm_exec.js diff --git a/.golangci.yml b/.golangci.yml index ffb0058..120faf2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,13 +1,145 @@ +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +run: + timeout: 5m + linters-settings: govet: - check-shadowing: true + enable: + - shadow misspell: locale: US + exhaustive: + default-signifies-exhaustive: true + gomodguard: + blocked: + modules: + - github.com/pkg/errors: + recommendations: + - errors + forbidigo: + analyze-types: true + forbid: + - ^fmt.Print(f|ln)?$ + - ^log.(Panic|Fatal|Print)(f|ln)?$ + - ^os.Exit$ + - ^panic$ + - ^print(ln)?$ + - p: ^testing.T.(Error|Errorf|Fatal|Fatalf|Fail|FailNow)$ + pkg: ^testing$ + msg: "use testify/assert instead" + varnamelen: + max-distance: 12 + min-name-length: 2 + ignore-type-assert-ok: true + ignore-map-index-ok: true + ignore-chan-recv-ok: true + ignore-decls: + - i int + - n int + - w io.Writer + - r io.Reader + - b []byte linters: - enable-all: true + enable: + - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers + - bidichk # Checks for dangerous unicode character sequences + - bodyclose # checks whether HTTP response body is closed successfully + - containedctx # containedctx is a linter that detects struct contained context.Context field + - contextcheck # check the function whether use a non-inherited context + - cyclop # checks function and package cyclomatic complexity + - decorder # check declaration order and count of types, constants, variables and functions + - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) + - dupl # Tool for code clone detection + - durationcheck # check for two durations multiplied together + - err113 # Golang linter to check the errors handling expressions + - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases + - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occations, where the check for the returned error can be omitted. + - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. + - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. + - exhaustive # check exhaustiveness of enum switch statements + - exportloopref # checks for pointers to enclosing loop variables + - forbidigo # Forbids identifiers + - forcetypeassert # finds forced type assertions + - gci # Gci control golang package import order and make it always deterministic. + - gochecknoglobals # Checks that no globals are present in Go code + - gocognit # Computes and checks the cognitive complexity of functions + - goconst # Finds repeated strings that could be replaced by a constant + - gocritic # The most opinionated Go source code linter + - gocyclo # Computes and checks the cyclomatic complexity of functions + - godot # Check if comments end in a period + - godox # Tool for detection of FIXME, TODO and other comment keywords + - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification + - gofumpt # Gofumpt checks whether code was gofumpt-ed. + - goheader # Checks is file header matches to pattern + - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports + - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. + - goprintffuncname # Checks that printf-like functions are named with `f` at the end + - gosec # Inspects source code for security problems + - gosimple # Linter for Go source code that specializes in simplifying a code + - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string + - grouper # An analyzer to analyze expression groups. + - importas # Enforces consistent import aliases + - ineffassign # Detects when assignments to existing variables are not used + - lll # Reports long lines + - maintidx # maintidx measures the maintainability index of each function. + - makezero # Finds slice declarations with non-zero initial length + - misspell # Finds commonly misspelled English words in comments + - nakedret # Finds naked returns in functions greater than a specified function length + - nestif # Reports deeply nested if statements + - nilerr # Finds the code that returns nil even if it checks that the error is not nil. + - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. + - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity + - noctx # noctx finds sending http request without context.Context + - predeclared # find code that shadows one of Go's predeclared identifiers + - revive # golint replacement, finds style mistakes + - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks + - stylecheck # Stylecheck is a replacement for golint + - tagliatelle # Checks the struct tags. + - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 + - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers + - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code + - unconvert # Remove unnecessary type conversions + - unparam # Reports unused function parameters + - unused # Checks Go code for unused constants, variables, functions and types + - varnamelen # checks that the length of a variable's name matches its scope + - wastedassign # wastedassign finds wasted assignment statements + - whitespace # Tool for detection of leading and trailing whitespace + disable: + - depguard # Go linter that checks if package imports are in a list of acceptable packages + - funlen # Tool for detection of long functions + - gochecknoinits # Checks that no init functions are present in Go code + - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. + - interfacebloat # A linter that checks length of interface. + - ireturn # Accept Interfaces, Return Concrete Types + - mnd # An analyzer to detect magic numbers + - nolintlint # Reports ill-formed or insufficient nolint directives + - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test + - prealloc # Finds slice declarations that could potentially be preallocated + - promlinter # Check Prometheus metrics naming via promlint + - rowserrcheck # checks whether Err of rows is checked successfully + - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. + - testpackage # linter that makes you use a separate _test package + - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes + - wrapcheck # Checks that errors returned from external packages are wrapped + - wsl # Whitespace Linter - Forces you to use empty lines! issues: exclude-use-default: false - max-per-linter: 0 - max-same-issues: 50 + exclude-dirs-use-default: false + exclude-rules: + # Allow complex tests and examples, better to be self contained + - path: (examples|main\.go) + linters: + - gocognit + - forbidigo + - path: _test\.go + linters: + - gocognit + + # Allow forbidden identifiers in CLI commands + - path: cmd + linters: + - forbidigo diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..30093e9 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +builds: +- skip: true diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000..4ce0569 --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,11 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Pion +Source: https://github.com/pion/ + +Files: README.md DESIGN.md **/README.md AUTHORS.txt renovate.json go.mod go.sum **/go.mod **/go.sum .eslintrc.json package.json examples.json sfu-ws/flutter/.gitignore sfu-ws/flutter/pubspec.yaml c-data-channels/webrtc.h examples/examples.json +Copyright: 2023 The Pion community +License: MIT + +Files: testdata/seed/* testdata/fuzz/* **/testdata/fuzz/* api/*.txt +Copyright: 2023 The Pion community +License: CC0-1.0 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b96a1ed..0000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go - -go: - - "1.x" # use the latest Go release - -env: - - GO111MODULE=on - -before_script: - - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.15.0 - -script: - - golangci-lint run ./... -# - rm -rf examples # Remove examples, no test coverage for them - - go test -coverpkg=$(go list ./... | tr '\n' ',') -coverprofile=cover.out -v -race -covermode=atomic ./... - - bash <(curl -s https://codecov.io/bash) - - bash .github/assert-contributors.sh - - bash .github/lint-disallowed-functions-in-library.sh - - bash .github/lint-commit-message.sh diff --git a/LICENSE b/LICENSE index ab60297..491caf6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,9 @@ MIT License -Copyright (c) 2018 +Copyright (c) 2023 The Pion community -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: +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 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. +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/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 0000000..2071b23 --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) + +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/README.md b/README.md index c15471d..20ae889 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@

The Pion logging library

Pion transport - Slack Widget + join us on Discord Follow us on Bluesky
- Build Status - GoDoc + GitHub Workflow Status + Go Reference Coverage Status Go Report Card License: MIT @@ -20,22 +20,15 @@ The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones. ### Community -Pion has an active community on the [Golang Slack](https://invite.slack.golangbridge.org/). Sign up and join the **#pion** channel for discussions and support. You can also use [Pion mailing list](https://groups.google.com/forum/#!forum/pion). +Pion has an active community on the [Discord](https://discord.gg/PngbdqpFbt). -We are always looking to support **your projects**. Please reach out if you have something to build! +Follow the [Pion Bluesky](https://bsky.app/profile/pion.ly) or [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news. +We are always looking to support **your projects**. Please reach out if you have something to build! If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly) ### Contributing -Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible: - -* [John Bradley](https://github.com/kc5nra) - *Original Author* -* [Sean DuBois](https://github.com/Sean-Der) - *Original Author* -* [Michael MacDonald](https://github.com/mjmac) - *Original Author* -* [Woodrow Douglass](https://github.com/wdouglass) - *Test coverage* -* [Michiel De Backker](https://github.com/backkem) - *Docs* -* [Hugo Arregui](https://github.com/hugoArregui) - *Custom Logs* -* [Justin Okamoto](https://github.com/justinokamoto) - *Disabled Logs Update* +Check out the [contributing wiki](https://github.com/pion/webrtc/wiki/Contributing) to join the group of amazing people making this project possible ### License MIT License - see [LICENSE](LICENSE) for full text diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..263e4d4 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,22 @@ +# +# DO NOT EDIT THIS FILE +# +# It is automatically copied from https://github.com/pion/.goassets repository. +# +# SPDX-FileCopyrightText: 2023 The Pion community +# SPDX-License-Identifier: MIT + +coverage: + status: + project: + default: + # Allow decreasing 2% of total coverage to avoid noise. + threshold: 2% + patch: + default: + target: 70% + only_pulls: true + +ignore: + - "examples/*" + - "examples/**/*" diff --git a/go.mod b/go.mod index a1b849b..acc2be9 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,11 @@ module github.com/pion/logging -go 1.12 +go 1.20 + +require github.com/stretchr/testify v1.10.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index e69de29..713a0b4 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/logger.go b/logger.go index 35f6505..eb1e56a 100644 --- a/logger.go +++ b/logger.go @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 The Pion community +// SPDX-License-Identifier: MIT + +// Package logging provides the logging library used by Pion package logging import ( @@ -9,8 +13,8 @@ import ( "sync" ) -// Use this abstraction to ensure thread-safe access to the logger's io.Writer -// (which could change at runtime) +// Use this abstraction to ensure thread-safe access to the logger's io.Writer. +// (which could change at runtime). type loggerWriter struct { sync.RWMutex output io.Writer @@ -25,11 +29,12 @@ func (lw *loggerWriter) SetOutput(output io.Writer) { func (lw *loggerWriter) Write(data []byte) (int, error) { lw.RLock() defer lw.RUnlock() + return lw.output.Write(data) } -// DefaultLeveledLogger encapsulates functionality for providing logging at -// user-defined levels +// DefaultLeveledLogger encapsulates functionality for providing logging at. +// user-defined levels. type DefaultLeveledLogger struct { level LogLevel writer *loggerWriter @@ -41,44 +46,50 @@ type DefaultLeveledLogger struct { } // WithTraceLogger is a chainable configuration function which sets the -// Trace-level logger +// Trace-level logger. func (ll *DefaultLeveledLogger) WithTraceLogger(log *log.Logger) *DefaultLeveledLogger { ll.trace = log + return ll } // WithDebugLogger is a chainable configuration function which sets the -// Debug-level logger +// Debug-level logger. func (ll *DefaultLeveledLogger) WithDebugLogger(log *log.Logger) *DefaultLeveledLogger { ll.debug = log + return ll } // WithInfoLogger is a chainable configuration function which sets the -// Info-level logger +// Info-level logger. func (ll *DefaultLeveledLogger) WithInfoLogger(log *log.Logger) *DefaultLeveledLogger { ll.info = log + return ll } // WithWarnLogger is a chainable configuration function which sets the -// Warn-level logger +// Warn-level logger. func (ll *DefaultLeveledLogger) WithWarnLogger(log *log.Logger) *DefaultLeveledLogger { ll.warn = log + return ll } // WithErrorLogger is a chainable configuration function which sets the -// Error-level logger +// Error-level logger. func (ll *DefaultLeveledLogger) WithErrorLogger(log *log.Logger) *DefaultLeveledLogger { ll.err = log + return ll } // WithOutput is a chainable configuration function which sets the logger's -// logging output to the supplied io.Writer +// logging output to the supplied io.Writer. func (ll *DefaultLeveledLogger) WithOutput(output io.Writer) *DefaultLeveledLogger { ll.writer.SetOutput(output) + return ll } @@ -94,70 +105,71 @@ func (ll *DefaultLeveledLogger) logf(logger *log.Logger, level LogLevel, format } } -// SetLevel sets the logger's logging level +// SetLevel sets the logger's logging level. func (ll *DefaultLeveledLogger) SetLevel(newLevel LogLevel) { ll.level.Set(newLevel) } -// Trace emits the preformatted message if the logger is at or below LogLevelTrace +// Trace emits the preformatted message if the logger is at or below LogLevelTrace. func (ll *DefaultLeveledLogger) Trace(msg string) { - ll.logf(ll.trace, LogLevelTrace, msg) + ll.logf(ll.trace, LogLevelTrace, msg) // nolint: govet } -// Tracef formats and emits a message if the logger is at or below LogLevelTrace +// Tracef formats and emits a message if the logger is at or below LogLevelTrace. func (ll *DefaultLeveledLogger) Tracef(format string, args ...interface{}) { ll.logf(ll.trace, LogLevelTrace, format, args...) } -// Debug emits the preformatted message if the logger is at or below LogLevelDebug +// Debug emits the preformatted message if the logger is at or below LogLevelDebug. func (ll *DefaultLeveledLogger) Debug(msg string) { - ll.logf(ll.debug, LogLevelDebug, msg) + ll.logf(ll.debug, LogLevelDebug, msg) // nolint: govet } -// Debugf formats and emits a message if the logger is at or below LogLevelDebug +// Debugf formats and emits a message if the logger is at or below LogLevelDebug. func (ll *DefaultLeveledLogger) Debugf(format string, args ...interface{}) { ll.logf(ll.debug, LogLevelDebug, format, args...) } -// Info emits the preformatted message if the logger is at or below LogLevelInfo +// Info emits the preformatted message if the logger is at or below LogLevelInfo. func (ll *DefaultLeveledLogger) Info(msg string) { - ll.logf(ll.info, LogLevelInfo, msg) + ll.logf(ll.info, LogLevelInfo, msg) // nolint: govet } -// Infof formats and emits a message if the logger is at or below LogLevelInfo +// Infof formats and emits a message if the logger is at or below LogLevelInfo. func (ll *DefaultLeveledLogger) Infof(format string, args ...interface{}) { ll.logf(ll.info, LogLevelInfo, format, args...) } -// Warn emits the preformatted message if the logger is at or below LogLevelWarn +// Warn emits the preformatted message if the logger is at or below LogLevelWarn. func (ll *DefaultLeveledLogger) Warn(msg string) { - ll.logf(ll.warn, LogLevelWarn, msg) + ll.logf(ll.warn, LogLevelWarn, msg) // nolint: govet } -// Warnf formats and emits a message if the logger is at or below LogLevelWarn +// Warnf formats and emits a message if the logger is at or below LogLevelWarn. func (ll *DefaultLeveledLogger) Warnf(format string, args ...interface{}) { ll.logf(ll.warn, LogLevelWarn, format, args...) } -// Error emits the preformatted message if the logger is at or below LogLevelError +// Error emits the preformatted message if the logger is at or below LogLevelError. func (ll *DefaultLeveledLogger) Error(msg string) { - ll.logf(ll.err, LogLevelError, msg) + ll.logf(ll.err, LogLevelError, msg) // nolint: govet } -// Errorf formats and emits a message if the logger is at or below LogLevelError +// Errorf formats and emits a message if the logger is at or below LogLevelError. func (ll *DefaultLeveledLogger) Errorf(format string, args ...interface{}) { ll.logf(ll.err, LogLevelError, format, args...) } -// NewDefaultLeveledLoggerForScope returns a configured LeveledLogger +// NewDefaultLeveledLoggerForScope returns a configured LeveledLogger. func NewDefaultLeveledLoggerForScope(scope string, level LogLevel, writer io.Writer) *DefaultLeveledLogger { if writer == nil { - writer = os.Stdout + writer = os.Stderr } logger := &DefaultLeveledLogger{ writer: &loggerWriter{output: writer}, level: level, } + return logger. WithTraceLogger(log.New(logger.writer, fmt.Sprintf("%s TRACE: ", scope), log.Lmicroseconds|log.Lshortfile)). WithDebugLogger(log.New(logger.writer, fmt.Sprintf("%s DEBUG: ", scope), log.Lmicroseconds|log.Lshortfile)). @@ -166,19 +178,19 @@ func NewDefaultLeveledLoggerForScope(scope string, level LogLevel, writer io.Wri WithErrorLogger(log.New(logger.writer, fmt.Sprintf("%s ERROR: ", scope), log.LstdFlags)) } -// DefaultLoggerFactory define levels by scopes and creates new DefaultLeveledLogger +// DefaultLoggerFactory define levels by scopes and creates new DefaultLeveledLogger. type DefaultLoggerFactory struct { Writer io.Writer DefaultLogLevel LogLevel ScopeLevels map[string]LogLevel } -// NewDefaultLoggerFactory creates a new DefaultLoggerFactory +// NewDefaultLoggerFactory creates a new DefaultLoggerFactory. func NewDefaultLoggerFactory() *DefaultLoggerFactory { factory := DefaultLoggerFactory{} factory.DefaultLogLevel = LogLevelError factory.ScopeLevels = make(map[string]LogLevel) - factory.Writer = os.Stdout + factory.Writer = os.Stderr logLevels := map[string]LogLevel{ "DISABLE": LogLevelDisabled, @@ -201,7 +213,10 @@ func NewDefaultLoggerFactory() *DefaultLoggerFactory { } if strings.ToLower(env) == "all" { - factory.DefaultLogLevel = level + if factory.DefaultLogLevel < level { + factory.DefaultLogLevel = level + } + continue } @@ -214,7 +229,7 @@ func NewDefaultLoggerFactory() *DefaultLoggerFactory { return &factory } -// NewLogger returns a configured LeveledLogger for the given , argsscope +// NewLogger returns a configured LeveledLogger for the given, argsscope. func (f *DefaultLoggerFactory) NewLogger(scope string) LeveledLogger { logLevel := f.DefaultLogLevel if f.ScopeLevels != nil { @@ -224,5 +239,6 @@ func (f *DefaultLoggerFactory) NewLogger(scope string) LeveledLogger { logLevel = scopeLevel } } + return NewDefaultLeveledLoggerForScope(scope, logLevel, f.Writer) } diff --git a/logging_test.go b/logging_test.go index 5b8c6e2..72faea0 100644 --- a/logging_test.go +++ b/logging_test.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: 2023 The Pion community +// SPDX-License-Identifier: MIT + package logging_test import ( @@ -7,108 +10,252 @@ import ( "testing" "github.com/pion/logging" + "github.com/stretchr/testify/assert" ) func testNoDebugLevel(t *testing.T, logger *logging.DefaultLeveledLogger) { + t.Helper() + var outBuf bytes.Buffer logger.WithOutput(&outBuf) logger.Debug("this shouldn't be logged") - if outBuf.Len() > 0 { - t.Error("Debug was logged when it shouldn't have been") - } + assert.GreaterOrEqual(t, 0, outBuf.Len(), "Debug was logged when it shouldn't have been") + logger.Debugf("this shouldn't be logged") - if outBuf.Len() > 0 { - t.Error("Debug was logged when it shouldn't have been") - } + assert.GreaterOrEqual(t, 0, outBuf.Len(), "Debug was logged when it shouldn't have been") } func testDebugLevel(t *testing.T, logger *logging.DefaultLeveledLogger) { + t.Helper() + var outBuf bytes.Buffer logger.WithOutput(&outBuf) dbgMsg := "this is a debug message" logger.Debug(dbgMsg) - if !strings.Contains(outBuf.String(), dbgMsg) { - t.Errorf("Expected to find %q in %q, but didn't", dbgMsg, outBuf.String()) - } - logger.Debugf(dbgMsg) - if !strings.Contains(outBuf.String(), dbgMsg) { - t.Errorf("Expected to find %q in %q, but didn't", dbgMsg, outBuf.String()) - } + assert.Truef(t, strings.Contains(outBuf.String(), dbgMsg), + "Expected to find %q in %q, but didn't", dbgMsg, outBuf.String()) + assert.Truef(t, strings.Contains(outBuf.String(), dbgMsg), + "Expected to find %q in %q, but didn't", dbgMsg, outBuf.String()) + + logger.Debugf(dbgMsg) // nolint: govet + assert.Truef(t, strings.Contains(outBuf.String(), dbgMsg), + "Expected to find %q in %q, but didn't", dbgMsg, outBuf.String()) } func testWarnLevel(t *testing.T, logger *logging.DefaultLeveledLogger) { + t.Helper() + var outBuf bytes.Buffer logger.WithOutput(&outBuf) warnMsg := "this is a warning message" logger.Warn(warnMsg) - if !strings.Contains(outBuf.String(), warnMsg) { - t.Errorf("Expected to find %q in %q, but didn't", warnMsg, outBuf.String()) - } - logger.Warnf(warnMsg) - if !strings.Contains(outBuf.String(), warnMsg) { - t.Errorf("Expected to find %q in %q, but didn't", warnMsg, outBuf.String()) - } + assert.Truef(t, strings.Contains(outBuf.String(), warnMsg), + "Expected to find %q in %q, but didn't", warnMsg, outBuf.String()) + + logger.Warnf(warnMsg) // nolint: govet + assert.Truef(t, strings.Contains(outBuf.String(), warnMsg), + "Expected to find %q in %q, but didn't", warnMsg, outBuf.String()) } func testErrorLevel(t *testing.T, logger *logging.DefaultLeveledLogger) { + t.Helper() + var outBuf bytes.Buffer logger.WithOutput(&outBuf) errMsg := "this is an error message" logger.Error(errMsg) - if !strings.Contains(outBuf.String(), errMsg) { - t.Errorf("Expected to find %q in %q, but didn't", errMsg, outBuf.String()) - } - logger.Errorf(errMsg) - if !strings.Contains(outBuf.String(), errMsg) { - t.Errorf("Expected to find %q in %q, but didn't", errMsg, outBuf.String()) - } + assert.Truef(t, strings.Contains(outBuf.String(), errMsg), + "Expected to find %q in %q but didn't", errMsg, outBuf.String()) + + logger.Errorf(errMsg) // nolint: govet + assert.Truef(t, strings.Contains(outBuf.String(), errMsg), + "Expected to find %q in %q but didn't", errMsg, outBuf.String()) +} + +func testTraceLevel(t *testing.T, logger *logging.DefaultLeveledLogger) { + t.Helper() + + var outBuf bytes.Buffer + logger.WithOutput(&outBuf) + + traceMsg := "trace message" + logger.Trace(traceMsg) + assert.Truef(t, strings.Contains(outBuf.String(), traceMsg), + "Expected to find %q in %q but didn't", traceMsg, outBuf.String()) + + logger.Tracef(traceMsg) // nolint: govet + assert.Truef(t, strings.Contains(outBuf.String(), traceMsg), + "Expected to find %q in %q but didn't", traceMsg, outBuf.String()) +} + +func testInfoLevel(t *testing.T, logger *logging.DefaultLeveledLogger) { + t.Helper() + + var outBuf bytes.Buffer + logger.WithOutput(&outBuf) + + infoMsg := "info message" + logger.Info(infoMsg) + assert.Truef(t, strings.Contains(outBuf.String(), infoMsg), + "Expected to find %q in %q but didn't", infoMsg, outBuf.String()) + + logger.Infof(infoMsg) // nolint: govet + assert.Truef(t, strings.Contains(outBuf.String(), infoMsg), + "Expected to find %q in %q but didn't", infoMsg, outBuf.String()) +} + +func testAllLevels(t *testing.T, logger *logging.DefaultLeveledLogger) { + t.Helper() + + testDebugLevel(t, logger) + testWarnLevel(t, logger) + testErrorLevel(t, logger) + testTraceLevel(t, logger) + testInfoLevel(t, logger) } func TestDefaultLoggerFactory(t *testing.T) { - f := logging.DefaultLoggerFactory{ - Writer: os.Stdout, + factory := logging.DefaultLoggerFactory{ + Writer: os.Stderr, DefaultLogLevel: logging.LogLevelWarn, ScopeLevels: map[string]logging.LogLevel{ "foo": logging.LogLevelDebug, }, } - logger := f.NewLogger("baz") + logger := factory.NewLogger("baz") bazLogger, ok := logger.(*logging.DefaultLeveledLogger) - if !ok { - t.Error("Invalid logger type") - } + assert.True(t, ok, "Invalid logger type") testNoDebugLevel(t, bazLogger) testWarnLevel(t, bazLogger) - logger = f.NewLogger("foo") + logger = factory.NewLogger("foo") fooLogger, ok := logger.(*logging.DefaultLeveledLogger) - if !ok { - t.Error("Invalid logger type") - } + assert.True(t, ok, "Invalid logger type") testDebugLevel(t, fooLogger) } func TestDefaultLogger(t *testing.T) { logger := logging. - NewDefaultLeveledLoggerForScope("test1", logging.LogLevelWarn, os.Stdout) + NewDefaultLeveledLoggerForScope("test1", logging.LogLevelWarn, os.Stderr) testNoDebugLevel(t, logger) testWarnLevel(t, logger) testErrorLevel(t, logger) } +func TestNewDefaultLoggerFactory(t *testing.T) { + factory := logging.NewDefaultLoggerFactory() + + disabled := factory.NewLogger("DISABLE") + errorLevel := factory.NewLogger("ERROR") + warnLevel := factory.NewLogger("WARN") + infoLevel := factory.NewLogger("INFO") + debugLevel := factory.NewLogger("DEBUG") + traceLevel := factory.NewLogger("TRACE") + + disabledLogger, ok := disabled.(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Missing disabled logger") + + errorLogger, ok := errorLevel.(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Missing error logger") + + warnLogger, ok := warnLevel.(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Missing warn logger") + + infoLogger, ok := infoLevel.(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Missing info logger") + + debugLogger, ok := debugLevel.(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Missing debug logger") + + traceLogger, ok := traceLevel.(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Missing trace logger") + + testNoDebugLevel(t, disabledLogger) + testNoDebugLevel(t, errorLogger) + testNoDebugLevel(t, warnLogger) + testNoDebugLevel(t, infoLogger) + testNoDebugLevel(t, debugLogger) + testNoDebugLevel(t, traceLogger) +} + +func TestNewDefaultLoggerFactoryLogAll(t *testing.T) { + t.Setenv("PION_LOG_ERROR", "all") + t.Setenv("PION_LOG_WARN", "all") + t.Setenv("PION_LOG_INFO", "all") + t.Setenv("PION_LOG_DEBUG", "all") + t.Setenv("PION_LOG_TRACE", "all") + + factory := logging.NewDefaultLoggerFactory() + + testAPI, ok := factory.NewLogger("test").(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Invalid logger factory type") + + testAllLevels(t, testAPI) +} + +func TestNewDefaultLoggerFactorySpecifcScopes(t *testing.T) { + t.Setenv("PION_LOG_DEBUG", "feature,rtp-logger") + + factory := logging.NewDefaultLoggerFactory() + + feature, ok := factory.NewLogger("feature").(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Invalid logger factory type") + + rtp, ok := factory.NewLogger("rtp-logger").(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Invalid logger factory type") + + noScope, ok := factory.NewLogger("no-scope").(*logging.DefaultLeveledLogger) + assert.True(t, ok, "Invalid logger factory type") + + testDebugLevel(t, feature) + testDebugLevel(t, rtp) + testNoDebugLevel(t, noScope) +} + func TestSetLevel(t *testing.T) { logger := logging. - NewDefaultLeveledLoggerForScope("testSetLevel", logging.LogLevelWarn, os.Stdout) + NewDefaultLeveledLoggerForScope("testSetLevel", logging.LogLevelWarn, os.Stderr) testNoDebugLevel(t, logger) logger.SetLevel(logging.LogLevelDebug) testDebugLevel(t, logger) } + +func TestLogLevel(t *testing.T) { + logLevel := logging.LogLevelDisabled + + logLevel.Set(logging.LogLevelError) + assert.Equal(t, logging.LogLevelError, logLevel.Get(), "LogLevel was not set to LogLevelError") +} + +func TestLogLevelString(t *testing.T) { + expected := map[logging.LogLevel]string{ + logging.LogLevelDisabled: "Disabled", + logging.LogLevelError: "Error", + logging.LogLevelWarn: "Warn", + logging.LogLevelInfo: "Info", + logging.LogLevelDebug: "Debug", + logging.LogLevelTrace: "Trace", + logging.LogLevel(999): "UNKNOWN", + } + + for level, expectedStr := range expected { + assert.Equal(t, expectedStr, level.String()) + } +} + +func TestNewDefaultLoggerStderr(t *testing.T) { + logger := logging.NewDefaultLeveledLoggerForScope("test", logging.LogLevelWarn, nil) + + testNoDebugLevel(t, logger) + testWarnLevel(t, logger) + testErrorLevel(t, logger) +} diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..f1bb98c --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "github>pion/renovate-config" + ] +} diff --git a/scoped.go b/scoped.go index 678bab4..7b3a550 100644 --- a/scoped.go +++ b/scoped.go @@ -1,18 +1,21 @@ +// SPDX-FileCopyrightText: 2023 The Pion community +// SPDX-License-Identifier: MIT + package logging import ( "sync/atomic" ) -// LogLevel represents the level at which the logger will emit log messages +// LogLevel represents the level at which the logger will emit log messages. type LogLevel int32 -// Set updates the LogLevel to the supplied value +// Set updates the LogLevel to the supplied value. func (ll *LogLevel) Set(newLevel LogLevel) { atomic.StoreInt32((*int32)(ll), int32(newLevel)) } -// Get retrieves the current LogLevel value +// Get retrieves the current LogLevel value. func (ll *LogLevel) Get() LogLevel { return LogLevel(atomic.LoadInt32((*int32)(ll))) } @@ -37,22 +40,22 @@ func (ll LogLevel) String() string { } const ( - // LogLevelDisabled completely disables logging of any events + // LogLevelDisabled completely disables logging of any events. LogLevelDisabled LogLevel = iota // LogLevelError is for fatal errors which should be handled by user code, - // but are logged to ensure that they are seen + // but are logged to ensure that they are seen. LogLevelError - // LogLevelWarn is for logging abnormal, but non-fatal library operation + // LogLevelWarn is for logging abnormal, but non-fatal library operation. LogLevelWarn - // LogLevelInfo is for logging normal library operation (e.g. state transitions, etc.) + // LogLevelInfo is for logging normal library operation (e.g. state transitions, etc.). LogLevelInfo - // LogLevelDebug is for logging low-level library information (e.g. internal operations) + // LogLevelDebug is for logging low-level library information (e.g. internal operations). LogLevelDebug - // LogLevelTrace is for logging very low-level library information (e.g. network traces) + // LogLevelTrace is for logging very low-level library information (e.g. network traces). LogLevelTrace ) -// LeveledLogger is the basic pion Logger interface +// LeveledLogger is the basic pion Logger interface. type LeveledLogger interface { Trace(msg string) Tracef(format string, args ...interface{}) @@ -66,7 +69,7 @@ type LeveledLogger interface { Errorf(format string, args ...interface{}) } -// LoggerFactory is the basic pion LoggerFactory interface +// LoggerFactory is the basic pion LoggerFactory interface. type LoggerFactory interface { NewLogger(scope string) LeveledLogger }