Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/janus-gateway/streaming/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func main() {
peerConnection, err := webrtc.New(config)
util.Check(err)


peerConnection.OnICEConnectionStateChange(func(connectionState ice.ConnectionState) {
fmt.Printf("Connection State has changed %s \n", connectionState.String())
})
Expand Down
91 changes: 91 additions & 0 deletions pkg/logging/logging.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package logging

import (
"io/ioutil"
"log"
"os"
)

type logLevel int

const(
Error = iota + 1
Warn
Info
Debug
Trace
)

// RTCPeerLogger is the default logging struct for rtcpeerconnection.
type RTCPeerLogger struct{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the overall goal should be to provide a generalized logging solution for various subsystems in pions-WebRTC, right? Rather than naming this RTCPeerLogger I'd suggest something like LeveledLogger? That's a little awkward to import as logging.LeveledLogger, but not the worst imo.

info, debug, warning,
trace, error *log.Logger
}

// webrtcLogger is the interface that must be implemented if a custom
// logger is used.
type webrtcLogger interface{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused about what this interface is used for -- it's not exported, so it can only be used internally to the logging package. But I don't see any use of it in logging.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was setting it a loging interface in order to have method in RTCPeerConnection which accepts the interface, and the user can pass a struct that allows them to do logging however they want. Ultimately a user would call a function pc.setLogger(myCustomLogger).

Info(msg string)
Trace(msg string)
Debug(msg string)
Warning(msg string)
Error(msg string)
}

func (pclog *RTCPeerLogger) Debug(debug string){
pclog.debug.Println(debug)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clear and simple, and the use of ioutil.Discard as the default writer makes sense from a functionality perspective. I have concerns about this approach from a performance perspective, however. For occasional logging e.g. at the Info/Warning level, I think overhead would be negligible. For copious logging at the Trace/Debug levels, I'm sure that we would start to see a lot of wasted resources spent formatting things in Println() just to throw them away.

Have a look at the source of printArg() to see how much work is happening behind the scenes -- it's pretty interesting.

I would propose instead using SetLoglevel() to set a level in the logger and then only calling Println() for the appropriate levels.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I read "Discard is an io.Writer on which all Write calls succeed without doing anything." and thought that it was not affecting performace. However if this is not the case then yeah we don't want to impact performance. This is my first time messing with the go logger, but if we can set a level in the logger and use that to determine what to print then that sounds good.

}

func (pclog *RTCPeerLogger) Error(error string){
pclog.error.Println(error)
}

func (pclog *RTCPeerLogger) Info(info string){
pclog.info.Println(info)
}

func (pclog *RTCPeerLogger) Warning(warning string){
pclog.warning.Println(warning)
}

func (pclog *RTCPeerLogger) Trace(trace string){
pclog.trace.Println(trace)
}

func (pclog *RTCPeerLogger) SetLogLevel(l logLevel) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good first pass, but unfortunately it would reconfigure the logging destinations every time SetLogLevel() is called. If we're going to go down the road of setting separate loggers for each log level, then I think it would make more sense to do this setup in a NewLogger() function and keep SetLogLevel() focused on simply changing the active logging level.

One way to make this nicely configurable might be to add With...() methods on your logger. So for example your NewLogger() would return a logger configured for opinionated and sane defaults, but that logger would have methods for doing things like setting the loglevel (e.g. .WithLogLevel(logging.Debug)), and logging destinations/configuration for various levels. For example, one might define a logger like so:

log := logging.NewLeveledLogger().
      WithLogLevel(logging.LogLevelDebug).
      WithDebugLogger(log.New(os.Stderr, "custom ", log.Lmicroseconds|log.Llongfile|log.LUTC))

log.Debug("o hai")

Copy link
Contributor Author

@aguilEA aguilEA Nov 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case that we do use levels for loging are you suggesting that we create logers like this?

Tracelog := logging.NewLeveledLogger().
WithLogLevel(logging.LogLevelTrace).
WithDebugLogger(log.New(os.Stderr, "trace ", log.Lmicroseconds|log.Llongfile|log.LUTC))

Debuglog := logging.NewLeveledLogger().
WithLogLevel(logging.LogLevelDebug).
WithDebugLogger(log.New(os.Stderr, "debug ", log.Lmicroseconds|log.Llongfile|log.LUTC))


debugOut := ioutil.Discard
infoOut := ioutil.Discard
traceOut := ioutil.Discard
warningOut := ioutil.Discard
errorOut := ioutil.Discard

switch l {
case Error:
errorOut = os.Stdout
case Warn:
errorOut = os.Stdout
warningOut = os.Stdout
case Info:
errorOut = os.Stdout
warningOut = os.Stdout
infoOut = os.Stdout
case Debug:
errorOut = os.Stdout
warningOut = os.Stdout
infoOut = os.Stdout
debugOut = os.Stdout
case Trace:
errorOut = os.Stdout
warningOut = os.Stdout
infoOut = os.Stdout
debugOut = os.Stdout
traceOut = os.Stdout
}

pclog.debug = log.New(debugOut, "DEBUG: ", log.Lshortfile)
pclog.info = log.New(infoOut, "INFO: ", log.Lshortfile)
pclog.trace = log.New(traceOut, "TRACE: ", log.Lshortfile)
pclog.warning = log.New(warningOut,"WARNING: ", log.Lshortfile)
pclog.error = log.New(errorOut, "ERROR: ", log.Lshortfile)
}
25 changes: 18 additions & 7 deletions rtcpeerconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"crypto/elliptic"
"crypto/rand"
"fmt"
"github.com/pions/webrtc/pkg/logging"
"net"
"strings"
"sync"
Expand All @@ -27,6 +28,7 @@ import (
// comparisons when no value was defined.
const Unknown = iota


// RTCPeerConnection represents a WebRTC connection that establishes a
// peer-to-peer communications with another RTCPeerConnection instance in a
// browser, or to another endpoint implementing the required protocols.
Expand Down Expand Up @@ -109,6 +111,10 @@ type RTCPeerConnection struct {

// Deprecated: Internal mechanism which will be removed.
networkManager *network.Manager

// Default Logging member
pclog *logging.RTCPeerLogger

}

// New creates a new RTCPeerConfiguration with the provided configuration
Expand Down Expand Up @@ -137,8 +143,11 @@ func New(configuration RTCConfiguration) (*RTCPeerConnection, error) {
mediaEngine: DefaultMediaEngine,
sctpTransport: newRTCSctpTransport(),
dataChannels: make(map[uint16]*RTCDataChannel),
pclog: &logging.RTCPeerLogger{},
}

pc.pclog.SetLogLevel(logging.Debug)

var err error
if err = pc.initConfiguration(configuration); err != nil {
return nil, err
Expand All @@ -159,7 +168,7 @@ func New(configuration RTCConfiguration) (*RTCPeerConnection, error) {

err = pc.networkManager.AddURL(url)
if err != nil {
fmt.Println(err)
pc.pclog.Debug(err.Error())
}
}
}
Expand Down Expand Up @@ -702,7 +711,7 @@ func (pc *RTCPeerConnection) SetRemoteDescription(desc RTCSessionDescription) er
if c := sdp.ICECandidateUnmarshal(*a.String()); c != nil {
pc.networkManager.IceAgent.AddRemoteCandidate(c)
} else {
fmt.Printf("Tried to parse ICE candidate, but failed %s ", a)
pc.pclog.Debug(fmt.Sprintf("Tried to parse ICE candidate, but failed %s ", a))
}
} else if strings.HasPrefix(*a.String(), "ice-ufrag") {
remoteUfrag = (*a.String())[len("ice-ufrag:"):]
Expand Down Expand Up @@ -1007,6 +1016,7 @@ func (pc *RTCPeerConnection) Close() error {
return nil
}


/* Everything below is private */
func (pc *RTCPeerConnection) generateChannel(ssrc uint32, payloadType uint8) (buffers chan<- *rtp.Packet) {
pc.RLock()
Expand All @@ -1018,13 +1028,13 @@ func (pc *RTCPeerConnection) generateChannel(ssrc uint32, payloadType uint8) (bu

sdpCodec, err := pc.CurrentLocalDescription.parsed.GetCodecForPayloadType(payloadType)
if err != nil {
fmt.Printf("No codec could be found in RemoteDescription for payloadType %d \n", payloadType)
pc.pclog.Debug(fmt.Sprintf("No codec could be found in RemoteDescription for payloadType %d \n", payloadType))
return nil
}

codec, err := pc.mediaEngine.getCodecSDP(sdpCodec)
if err != nil {
fmt.Printf("Codec %s in not registered\n", sdpCodec)
pc.pclog.Debug(fmt.Sprintf("Codec %s in not registered\n", sdpCodec))
return nil
}

Expand Down Expand Up @@ -1074,7 +1084,7 @@ func (pc *RTCPeerConnection) dataChannelEventHandler(e network.DataChannelEvent)
dc.onMessage(event.Payload)
} else {
pc.RUnlock()
fmt.Printf("No datachannel found for streamIdentifier %d \n", e.StreamIdentifier())
pc.pclog.Debug(fmt.Sprintf("No datachannel found for streamIdentifier %d \n", e.StreamIdentifier()))
}
case *network.DataChannelOpen:
pc.RLock()
Expand All @@ -1083,7 +1093,7 @@ func (pc *RTCPeerConnection) dataChannelEventHandler(e network.DataChannelEvent)
dc.Lock()
err := dc.sendOpenChannelMessage()
if err != nil {
fmt.Println("failed to send openchannel", err)
pc.pclog.Debug("failed to send openchannel" + err.Error())
dc.Unlock()
continue
}
Expand All @@ -1093,7 +1103,7 @@ func (pc *RTCPeerConnection) dataChannelEventHandler(e network.DataChannelEvent)
dc.onOpen() // TODO: move to ChannelAck handling
}
default:
fmt.Printf("Unhandled DataChannelEvent %v \n", event)
pc.pclog.Debug(fmt.Sprintf("Unhandled DataChannelEvent %v \n", event))
}
}

Expand Down Expand Up @@ -1290,3 +1300,4 @@ func (pc *RTCPeerConnection) newRTCRtpTransceiver(
pc.rtpTransceivers = append(pc.rtpTransceivers, t)
return t
}