snapshot of https://github.com/pion/webrtc.git (main, 2026-09-15; blobs > 131072B omitted)
Some checks failed
REUSE Compliance Check / lint (push) Failing after 0s
Browser E2E / Test (push) Failing after 3s
Test / test (1.24) (push) Failing after 0s
Test / test-i386 (1.25) (push) Failing after 0s
Test / test-i386 (1.24) (push) Failing after 0s
Test / test-windows (1.25) (push) Failing after 0s
Test / test-windows (1.24) (push) Failing after 0s
Test / test (1.25) (push) Failing after 0s
Examples Tests / Test (push) Failing after 3s
Test / test-macos (1.25) (push) Failing after 0s
Test / test-macos (1.24) (push) Failing after 0s
Go mod tidy / tidy (push) Failing after 0s
Test / test-wasm (push) Failing after 0s
CodeQL / analyze (push) Failing after 1s
Fuzz / fuzz (push) Failing after 0s
Some checks failed
REUSE Compliance Check / lint (push) Failing after 0s
Browser E2E / Test (push) Failing after 3s
Test / test (1.24) (push) Failing after 0s
Test / test-i386 (1.25) (push) Failing after 0s
Test / test-i386 (1.24) (push) Failing after 0s
Test / test-windows (1.25) (push) Failing after 0s
Test / test-windows (1.24) (push) Failing after 0s
Test / test (1.25) (push) Failing after 0s
Examples Tests / Test (push) Failing after 3s
Test / test-macos (1.25) (push) Failing after 0s
Test / test-macos (1.24) (push) Failing after 0s
Go mod tidy / tidy (push) Failing after 0s
Test / test-wasm (push) Failing after 0s
CodeQL / analyze (push) Failing after 1s
Fuzz / fuzz (push) Failing after 0s
This commit is contained in:
56
examples/custom-logger/README.md
Normal file
56
examples/custom-logger/README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# custom-logger
|
||||
|
||||
`custom-logger` is an example demonstrating how to override the default logging behavior of the [Pion WebRTC](https://github.com/pion/webrtc) stack.
|
||||
By default, Pion logs everything to `stdout`.
|
||||
This example shows how to inject a **custom `LoggerFactory`** to handle logs from every subsystem (ICE, DTLS, SCTP, DataChannel...).
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- Creates a **custom logger** that implements `logging.LeveledLogger`.
|
||||
- Initializes two peer connections (`offerer` and `answerer`) locally.
|
||||
- Establishes a WebRTC connection between them.
|
||||
- Logs events from:
|
||||
- `ICE` candidate gathering
|
||||
- `DTLS` handshake
|
||||
- `SCTP` and `DataChannel` setup
|
||||
- Prints logs with clear prefixes like `customLogger Debug:`.
|
||||
|
||||
Ideal for:
|
||||
- Integrate with external monitoring systems
|
||||
- Store logs to files or databases
|
||||
- Debug complex WebRTC flows in a structured way
|
||||
|
||||
---
|
||||
|
||||
## How to run
|
||||
|
||||
### 1. Install the example
|
||||
|
||||
```
|
||||
go install github.com/pion/webrtc/v4/examples/custom-logger@latest
|
||||
```
|
||||
Make sure ```$(go env GOPATH)/bin ``` is in your ```PATH```.
|
||||
|
||||
You can add it to your PATH like this (zsh):
|
||||
|
||||
```
|
||||
echo 'export PATH="$PATH:$(go env GOPATH)/bin"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
### 2.Run
|
||||
`custom-logger` or `go run main.go`
|
||||
|
||||
## Example output
|
||||
|
||||
```
|
||||
Creating logger for ice
|
||||
Creating logger for dtls
|
||||
Peer Connection State has changed: connected (answerer)
|
||||
Peer Connection State has changed: connected (offerer)
|
||||
customLogger Debug: Adding a new peer-reflexive candidate: 10.8.21.1:51196
|
||||
```
|
||||
|
||||
|
||||
You should see messages from our customLogger, as two PeerConnections start a session
|
||||
184
examples/custom-logger/main.go
Normal file
184
examples/custom-logger/main.go
Normal file
@@ -0,0 +1,184 @@
|
||||
// SPDX-FileCopyrightText: 2026 The Pion community <https://pion.ly>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build !js
|
||||
|
||||
// custom-logger is an example of how the Pion API provides an customizable logging API
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/pion/logging"
|
||||
"github.com/pion/webrtc/v4"
|
||||
)
|
||||
|
||||
// Everything below is the Pion WebRTC API! Thanks for using it ❤️.
|
||||
|
||||
// customLogger satisfies the interface logging.LeveledLogger
|
||||
// a logger is created per subsystem in Pion, so you can have custom
|
||||
// behavior per subsystem (ICE, DTLS, SCTP...)
|
||||
type customLogger struct{}
|
||||
|
||||
// Print all messages except trace.
|
||||
func (c customLogger) Trace(string) {}
|
||||
func (c customLogger) Tracef(string, ...any) {}
|
||||
|
||||
func (c customLogger) Debug(msg string) { fmt.Printf("customLogger Debug: %s\n", msg) }
|
||||
func (c customLogger) Debugf(format string, args ...any) {
|
||||
c.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
func (c customLogger) Info(msg string) { fmt.Printf("customLogger Info: %s\n", msg) }
|
||||
func (c customLogger) Infof(format string, args ...any) {
|
||||
c.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
func (c customLogger) Warn(msg string) { fmt.Printf("customLogger Warn: %s\n", msg) }
|
||||
func (c customLogger) Warnf(format string, args ...any) {
|
||||
c.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
func (c customLogger) Error(msg string) { fmt.Printf("customLogger Error: %s\n", msg) }
|
||||
func (c customLogger) Errorf(format string, args ...any) {
|
||||
c.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// customLoggerFactory satisfies the interface logging.LoggerFactory
|
||||
// This allows us to create different loggers per subsystem. So we can
|
||||
// add custom behavior.
|
||||
type customLoggerFactory struct{}
|
||||
|
||||
func (c customLoggerFactory) NewLogger(subsystem string) logging.LeveledLogger {
|
||||
fmt.Printf("Creating logger for %s \n", subsystem)
|
||||
|
||||
return customLogger{}
|
||||
}
|
||||
|
||||
// nolint: cyclop
|
||||
func main() {
|
||||
// Create a new API with a custom logger
|
||||
// This SettingEngine allows non-standard WebRTC behavior
|
||||
s := webrtc.SettingEngine{
|
||||
LoggerFactory: customLoggerFactory{},
|
||||
}
|
||||
api := webrtc.NewAPI(webrtc.WithSettingEngine(s))
|
||||
|
||||
// Create a new RTCPeerConnection
|
||||
offerPeerConnection, err := api.NewPeerConnection(webrtc.Configuration{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if cErr := offerPeerConnection.Close(); cErr != nil {
|
||||
fmt.Printf("cannot close offerPeerConnection: %v\n", cErr)
|
||||
}
|
||||
}()
|
||||
|
||||
// We need a DataChannel so we can have ICE Candidates
|
||||
if _, err = offerPeerConnection.CreateDataChannel("custom-logger", nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create a new RTCPeerConnection
|
||||
answerPeerConnection, err := api.NewPeerConnection(webrtc.Configuration{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if cErr := answerPeerConnection.Close(); cErr != nil {
|
||||
fmt.Printf("cannot close answerPeerConnection: %v\n", cErr)
|
||||
}
|
||||
}()
|
||||
|
||||
// Set the handler for Peer connection state
|
||||
// This will notify you when the peer has connected/disconnected
|
||||
offerPeerConnection.OnConnectionStateChange(func(state webrtc.PeerConnectionState) {
|
||||
fmt.Printf("Peer Connection State has changed: %s (offerer)\n", state.String())
|
||||
|
||||
if state == webrtc.PeerConnectionStateFailed {
|
||||
// Wait until PeerConnection has had no network activity for 30 seconds or another failure.
|
||||
// It may be reconnected using an ICE Restart.
|
||||
// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
|
||||
// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
|
||||
fmt.Println("Peer Connection has gone to failed exiting")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if state == webrtc.PeerConnectionStateClosed {
|
||||
// PeerConnection was explicitly closed. This usually happens from a DTLS CloseNotify
|
||||
fmt.Println("Peer Connection has gone to closed exiting")
|
||||
os.Exit(0)
|
||||
}
|
||||
})
|
||||
|
||||
// Set the handler for Peer connection state
|
||||
// This will notify you when the peer has connected/disconnected
|
||||
answerPeerConnection.OnConnectionStateChange(func(state webrtc.PeerConnectionState) {
|
||||
fmt.Printf("Peer Connection State has changed: %s (answerer)\n", state.String())
|
||||
|
||||
if state == webrtc.PeerConnectionStateFailed {
|
||||
// Wait until PeerConnection has had no network activity for 30 seconds or another failure.
|
||||
// It may be reconnected using an ICE Restart.
|
||||
// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
|
||||
// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
|
||||
fmt.Println("Peer Connection has gone to failed exiting")
|
||||
os.Exit(0)
|
||||
}
|
||||
})
|
||||
|
||||
// Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
|
||||
// send it to the other peer
|
||||
answerPeerConnection.OnICECandidate(func(candidate *webrtc.ICECandidate) {
|
||||
if candidate != nil {
|
||||
if iceErr := offerPeerConnection.AddICECandidate(candidate.ToJSON()); iceErr != nil {
|
||||
panic(iceErr)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
|
||||
// send it to the other peer
|
||||
offerPeerConnection.OnICECandidate(func(candidate *webrtc.ICECandidate) {
|
||||
if candidate != nil {
|
||||
if iceErr := answerPeerConnection.AddICECandidate(candidate.ToJSON()); iceErr != nil {
|
||||
panic(iceErr)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Create an offer for the other PeerConnection
|
||||
offer, err := offerPeerConnection.CreateOffer(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// SetLocalDescription, needed before remote gets offer
|
||||
if err = offerPeerConnection.SetLocalDescription(offer); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Take offer from remote, answerPeerConnection is now able to contact
|
||||
// the other PeerConnection
|
||||
if err = answerPeerConnection.SetRemoteDescription(offer); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create an Answer to send back to our originating PeerConnection
|
||||
answer, err := answerPeerConnection.CreateAnswer(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Set the answerer's LocalDescription
|
||||
if err = answerPeerConnection.SetLocalDescription(answer); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// SetRemoteDescription on original PeerConnection, this finishes our signaling
|
||||
// bother PeerConnections should be able to communicate with each other now
|
||||
if err = offerPeerConnection.SetRemoteDescription(answer); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Block forever
|
||||
select {}
|
||||
}
|
||||
Reference in New Issue
Block a user