Fail-fast switch for logging Logging, format

This commit is contained in:
eyedeekay
2024-11-16 13:15:33 -05:00
parent df45c19272
commit 4ad0f97bfe
5 changed files with 131 additions and 43 deletions

View File

@ -41,7 +41,7 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Elligator2 - [ ] Elligator2
- [ ] HKDF - [ ] HKDF
- [ ] HMAC - [ ] HMAC
- [/] Noise subsystem - [X] Noise subsystem
- End-to-End Crypto - End-to-End Crypto
- [ ] Garlic messages - [ ] Garlic messages
- [ ] ElGamal/AES+SessionTag - [ ] ElGamal/AES+SessionTag
@ -94,7 +94,7 @@ please keep up with these changes, as they will not be backward compatible and r
- [X] Session Tag - [X] Session Tag
## Verbosity ## ## Verbosity ##
Logging can be enabled and configured using the DEBUG_I2P environment variable. By default, logging is disabled. Logging can be enabled and configured using the `DEBUG_I2P` environment variable. By default, logging is disabled.
There are three available log levels: There are three available log levels:
@ -113,6 +113,17 @@ export DEBUG_I2P=error
If DEBUG_I2P is set to an unrecognized variable, it will fall back to "debug". If DEBUG_I2P is set to an unrecognized variable, it will fall back to "debug".
## Fast-Fail mode ##
Fast-Fail mode can be activated by setting `WARNFAIL_I2P` to any non-empty value. When set, every warning or error is Fatal.
It is unsafe for production use, and intended only for debugging and testing purposes.
```shell
export WARNFAIL_I2P=true
```
If `WARNFAIL_I2P` is set and `DEBUG_I2P` is unset, `DEBUG_I2P` will be set to `debug`.
## Contributing ## Contributing
See CONTRIBUTING.md for more information. See CONTRIBUTING.md for more information.

View File

@ -212,39 +212,39 @@ func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, er
// NewCertificate creates a new Certificate with default NULL type // NewCertificate creates a new Certificate with default NULL type
func NewCertificate() *Certificate { func NewCertificate() *Certificate {
return &Certificate{ return &Certificate{
kind: Integer([]byte{CERT_NULL}), kind: Integer([]byte{CERT_NULL}),
len: Integer([]byte{0}), len: Integer([]byte{0}),
payload: make([]byte, 0), payload: make([]byte, 0),
} }
} }
// NewCertificateWithType creates a new Certificate with specified type and payload // NewCertificateWithType creates a new Certificate with specified type and payload
func NewCertificateWithType(certType uint8, payload []byte) (*Certificate, error) { func NewCertificateWithType(certType uint8, payload []byte) (*Certificate, error) {
// Validate certificate type // Validate certificate type
switch certType { switch certType {
case CERT_NULL, CERT_HASHCASH, CERT_HIDDEN, CERT_SIGNED, CERT_MULTIPLE, CERT_KEY: case CERT_NULL, CERT_HASHCASH, CERT_HIDDEN, CERT_SIGNED, CERT_MULTIPLE, CERT_KEY:
// Valid type // Valid type
default: default:
return nil, fmt.Errorf("invalid certificate type: %d", certType) return nil, fmt.Errorf("invalid certificate type: %d", certType)
} }
// For NULL certificates, payload should be empty // For NULL certificates, payload should be empty
if certType == CERT_NULL && len(payload) > 0 { if certType == CERT_NULL && len(payload) > 0 {
return nil, errors.New("NULL certificates must have empty payload") return nil, errors.New("NULL certificates must have empty payload")
} }
length, _ := NewIntegerFromInt(len(payload), 2) length, _ := NewIntegerFromInt(len(payload), 2)
cert := &Certificate{
kind: Integer([]byte{certType}),
len: *length,
payload: make([]byte, len(payload)),
}
// Copy payload if present cert := &Certificate{
if len(payload) > 0 { kind: Integer([]byte{certType}),
copy(cert.payload, payload) len: *length,
} payload: make([]byte, len(payload)),
}
return cert, nil // Copy payload if present
} if len(payload) > 0 {
copy(cert.payload, payload)
}
return cert, nil
}

View File

@ -165,4 +165,3 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
return return
} }

View File

@ -21,11 +21,11 @@ type NoiseSession struct {
*sync.Cond *sync.Cond
*NoiseTransport // The parent transport, which "Dialed" the connection to the peer whith whom we established the session *NoiseTransport // The parent transport, which "Dialed" the connection to the peer whith whom we established the session
*HandshakeState *HandshakeState
RecvQueue *cb.Queue RecvQueue *cb.Queue
SendQueue *cb.Queue SendQueue *cb.Queue
VerifyCallback VerifyCallbackFunc VerifyCallback VerifyCallbackFunc
activeCall int32 activeCall int32
Conn net.Conn Conn net.Conn
} }
// RemoteAddr implements net.Conn // RemoteAddr implements net.Conn

View File

@ -1,7 +1,7 @@
package logger package logger
import ( import (
"io/ioutil" "io"
"os" "os"
"strings" "strings"
"sync" "sync"
@ -10,18 +10,96 @@ import (
) )
var ( var (
log *logrus.Logger log *Logger
once sync.Once once sync.Once
failFast string
) )
// Logger wraps logrus.Logger and adds the ability to make all warnings fatal
type Logger struct {
*logrus.Logger
}
// Entry wraps logrus.Entry and enables it to use our Logger
type Entry struct {
Logger
entry *logrus.Entry
}
// Warn wraps logrus.Warn and logs a fatal error if failFast is set
func (l *Logger) Warn(args ...interface{}) {
warnFatal(args)
l.Logger.Warn(args...)
}
// Warnf wraps logrus.Warnf and logs a fatal error if failFast is set
func (l *Logger) Warnf(format string, args ...interface{}) {
warnFatalf(format, args...)
l.Logger.Warnf(format, args...)
}
// Error wraps logrus.Error and logs a fatal error if failFast is set
func (l *Logger) Error(args ...interface{}) {
warnFatal(args)
l.Logger.Error(args...)
}
// Errorf wraps logrus.Errorf and logs a fatal error if failFast is set
func (l *Logger) Errorf(format string, args ...interface{}) {
warnFatalf(format, args...)
l.Logger.Errorf(format, args...)
}
// WithField wraps logrus.WithField and returns an Entry
func (l *Logger) WithField(key string, value interface{}) *Entry {
entry := l.Logger.WithField(key, value)
return &Entry{*l, entry}
}
// WithFields wraps logrus.WithFields and returns an Entry
func (l *Logger) WithFields(fields logrus.Fields) *Entry {
entry := l.Logger.WithFields(fields)
return &Entry{*l, entry}
}
// WithError wraps logrus.WithError and returns an Entry
func (l *Logger) WithError(err error) *Entry {
entry := l.Logger.WithError(err)
return &Entry{*l, entry}
}
func warnFatal(args ...interface{}) {
if failFast != "" {
log.Fatal(args)
}
}
func warnFatalf(format string, args ...interface{}) {
if failFast != "" {
log.Fatalf(format, args...)
}
}
func warnFail() {
if failFast != "" {
log.Error("FATAL ERROR")
}
}
// InitializeGoI2PLogger sets up all the necessary logging
func InitializeGoI2PLogger() { func InitializeGoI2PLogger() {
once.Do(func() { once.Do(func() {
log = logrus.New() log = &Logger{}
log.Logger = logrus.New()
// We do not want to log by default // We do not want to log by default
log.SetOutput(ioutil.Discard) log.SetOutput(io.Discard)
log.SetLevel(logrus.PanicLevel) log.SetLevel(logrus.PanicLevel)
// Check if DEBUG_I2P is set // Check if DEBUG_I2P is set
if logLevel := os.Getenv("DEBUG_I2P"); logLevel != "" { if logLevel := os.Getenv("DEBUG_I2P"); logLevel != "" {
failFast = os.Getenv("WARNFAIL_I2P")
if failFast != "" && logLevel == "" {
logLevel = "debug"
}
log.SetOutput(os.Stdout) log.SetOutput(os.Stdout)
switch strings.ToLower(logLevel) { switch strings.ToLower(logLevel) {
case "debug": case "debug":
@ -38,8 +116,8 @@ func InitializeGoI2PLogger() {
}) })
} }
// GetGoI2PLogger returns the initialized logger // GetGoI2PLogger returns the initialized Logger
func GetGoI2PLogger() *logrus.Logger { func GetGoI2PLogger() *Logger {
if log == nil { if log == nil {
InitializeGoI2PLogger() InitializeGoI2PLogger()
} }