1
0
mirror of https://github.com/taigrr/log-socket synced 2025-01-18 04:53:14 -08:00

3 Commits

12 changed files with 503 additions and 222 deletions

View File

@@ -1,4 +1,4 @@
Copyright (C) 2019-2021 by Tai Groot <tai@taigrr.com> Copyright (C) 2019-2022 by Tai Groot <tai@taigrr.com>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted. purpose with or without fee is hereby granted.

View File

@@ -1,6 +1,7 @@
package browser package browser
import ( import (
_ "embed"
"html/template" "html/template"
"net/http" "net/http"
"strings" "strings"
@@ -17,201 +18,7 @@ func LogSocketViewHandler(w http.ResponseWriter, r *http.Request) {
homeTemplate.Execute(w, wsResource) homeTemplate.Execute(w, wsResource)
} }
var homeTemplate = template.Must(template.New("").Parse(` //go:embed viewer.html
<!DOCTYPE html> var webpage string
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<center>
<input type="text" id="search" onkeyup="filterTable()" placeholder="Filter...">
<input type="checkbox" id="shouldScroll" checked>Enable Autoscroll<br>
<table id="logHeaders" style="text-align:left; width:80%;" >
<tbody>
<tr class="header">
<th style="width:20%;">TimeStamp</th>
<th style="width:5%;">Level</th>
<th style="width:65%;">Output</th>
<th style="width:10%;">Source</th>
</tr>
</tbody>
</table>
<div id="tableWrapper"> var homeTemplate = template.Must(template.New("").Parse(webpage))
<table id="logs" style="text-align:left; width:100%;" >
<tbody id="tbodylogs">
<tr class="header">
<th style="width:20%;"></th>
<th style="width:5%;"></th>
<th style="width:65%;"></th>
<th style="width:10%;"></th>
</tr>
</tbody>
</table>
</div>
<br>
<input class="button" type="button" id="download" value="Download Logs" style="background-color:#3f51b5;"/>
<input class="button" type="button" id="delete" value="Delete Logs" style="background-color:#f44336"/>
</center>
</body>
<footer>
<style>
#tableWrapper{
overflow-y: scroll;
display: flow-root;
width: 80%;
height: 80vh;
}
td,tr{
height: min-content;
}
.button{
display: inline-block;
width: 5vw;
height: 5vh;
}
</style>
<script>
var logTable = document.getElementById("logs");
var logTableB = document.getElementById("tbodylogs");
var ws = null;
var application = "demo-commit"
var logs = [];
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function download(filename, text) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function openSocket() {
if (ws) {
return false;
}
ws = new WebSocket("{{.}}");
ws.onclose = async function(evt) {
ws = null;
while(ws == null){
openSocket()
await sleep(5000);
}
}
ws.onmessage = function(evt) {
var entry = JSON.parse(evt.data)
logs.push(entry)
var row = document.createElement('tr');
var ts = document.createElement('td');
var tst = document.createTextNode(entry.timestamp);
ts.appendChild(tst);
row.appendChild(ts);
var ts = document.createElement('td');
var tst = document.createTextNode(entry.level);
ts.appendChild(tst);
row.appendChild(ts);
var ts = document.createElement('td');
var tst = document.createTextNode(entry.output);
ts.appendChild(tst);
row.appendChild(ts);
var ts = document.createElement('td');
var tst = document.createTextNode(entry.file);
ts.appendChild(tst);
row.appendChild(ts);
var bg="";
switch(entry.level){
case "INFO":
bg="white";
break;
case "ERROR":
bg="#f44336";
break;
case "WARN":
bg="#fb8c00"
break;
case "TRACE":
bg="#E1F5FE"
break;
case "DEBUG":
bg="#B3E5FC"
break;
default:
bg="white"
break;
}
row.style.backgroundColor=bg
logTableB.append(row)
filterTable()
}
ws.onerror = function(evt) {
if (evt != null && evt.data != null){
// handle error here
}
}
}
function clearTable(){
if(!window.confirm("Are you sure you want to delete all logs?")){
return
}
logs = []
while (logTableB.childNodes.length > 1) {
logTableB.removeChild(logTableB.childNodes[1]);
}
}
function filterTable() {
var cols, input, filter, table, tr, td, i, txtValue, w;
input = document.getElementById("search");
filter = input.value;
table = logTableB;
tr = table.getElementsByTagName("tr");
for (i = 1; i < tr.length; i++) {
cols = tr[i].getElementsByTagName("td");
var visible = false;
for (w = 0; w < cols.length; w++){
if (!visible && cols[w]) {
td = cols[w]
txtValue = td.textContent || td.innerText;
if (txtValue.indexOf(filter) > -1) {
visible = true
}
}
}
if(visible){
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
function pageScroll() {
if (document.getElementById('shouldScroll').checked) {
document.getElementById('tableWrapper').scrollBy(0,10);
}
setTimeout(pageScroll,10);
}
document.getElementById("delete").addEventListener("click", function(){
clearTable()
}, false);
document.getElementById("download").addEventListener("click", function(){
download(application+'.json',JSON.stringify(logs));
}, false);
openSocket();
pageScroll();
</script>
</footer>
</html>
`))

196
browser/viewer.html Normal file
View File

@@ -0,0 +1,196 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<center>
<input type="text" id="search" onkeyup="filterTable()" placeholder="Filter...">
<input type="checkbox" id="shouldScroll" checked>Enable Autoscroll<br>
<table id="logHeaders" style="text-align:left; width:80%;" >
<tbody>
<tr class="header">
<th style="width:20%;">TimeStamp</th>
<th style="width:5%;">Level</th>
<th style="width:65%;">Output</th>
<th style="width:10%;">Source</th>
</tr>
</tbody>
</table>
<div id="tableWrapper">
<table id="logs" style="text-align:left; width:100%;" >
<tbody id="tbodylogs">
<tr class="header">
<th style="width:20%;"></th>
<th style="width:5%;"></th>
<th style="width:65%;"></th>
<th style="width:10%;"></th>
</tr>
</tbody>
</table>
</div>
<br>
<input class="button" type="button" id="download" value="Download Logs" style="background-color:#3f51b5;"/>
<input class="button" type="button" id="delete" value="Delete Logs" style="background-color:#f44336"/>
</center>
</body>
<footer>
<style>
#tableWrapper{
overflow-y: scroll;
display: flow-root;
width: 80%;
height: 80vh;
}
td,tr{
height: min-content;
}
.button{
display: inline-block;
width: 5vw;
height: 5vh;
}
</style>
<script>
var logTable = document.getElementById("logs");
var logTableB = document.getElementById("tbodylogs");
var ws = null;
var application = "demo-commit"
var logs = [];
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function download(filename, text) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function openSocket() {
if (ws) {
return false;
}
ws = new WebSocket("{{.}}");
ws.onclose = async function(evt) {
ws = null;
while(ws == null){
openSocket()
await sleep(5000);
}
}
ws.onmessage = function(evt) {
var entry = JSON.parse(evt.data)
logs.push(entry)
var row = document.createElement('tr');
var ts = document.createElement('td');
var tst = document.createTextNode(entry.timestamp);
ts.appendChild(tst);
row.appendChild(ts);
var ts = document.createElement('td');
var tst = document.createTextNode(entry.level);
ts.appendChild(tst);
row.appendChild(ts);
var ts = document.createElement('td');
var tst = document.createTextNode(entry.output);
ts.appendChild(tst);
row.appendChild(ts);
var ts = document.createElement('td');
var tst = document.createTextNode(entry.file);
ts.appendChild(tst);
row.appendChild(ts);
var bg="";
switch(entry.level){
case "INFO":
bg="white";
break;
case "ERROR":
bg="#f44336";
break;
case "WARN":
bg="#fb8c00"
break;
case "TRACE":
bg="#E1F5FE"
break;
case "DEBUG":
bg="#B3E5FC"
break;
default:
bg="white"
break;
}
row.style.backgroundColor=bg
logTableB.append(row)
filterTable()
}
ws.onerror = function(evt) {
if (evt != null && evt.data != null){
// handle error here
}
}
}
function clearTable(){
if(!window.confirm("Are you sure you want to delete all logs?")){
return
}
logs = []
while (logTableB.childNodes.length > 1) {
logTableB.removeChild(logTableB.childNodes[1]);
}
}
function filterTable() {
var cols, input, filter, table, tr, td, i, txtValue, w;
input = document.getElementById("search");
filter = input.value;
table = logTableB;
tr = table.getElementsByTagName("tr");
for (i = 1; i < tr.length; i++) {
cols = tr[i].getElementsByTagName("td");
var visible = false;
for (w = 0; w < cols.length; w++){
if (!visible && cols[w]) {
td = cols[w]
txtValue = td.textContent || td.innerText;
if (txtValue.indexOf(filter) > -1) {
visible = true
}
}
}
if(visible){
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
function pageScroll() {
if (document.getElementById('shouldScroll').checked) {
document.getElementById('tableWrapper').scrollBy(0,10);
}
setTimeout(pageScroll,10);
}
document.getElementById("delete").addEventListener("click", function(){
clearTable()
}, false);
document.getElementById("download").addEventListener("click", function(){
download(application+'.json',JSON.stringify(logs));
}, false);
openSocket();
pageScroll();
</script>
</footer>
</html>

4
go.mod
View File

@@ -1,5 +1,5 @@
module github.com/taigrr/log-socket module github.com/taigrr/log-socket
go 1.17 go 1.18
require github.com/gorilla/websocket v1.4.2 require github.com/gorilla/websocket v1.5.0

4
go.sum
View File

@@ -1,2 +1,2 @@
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=

136
log/gaplogger.go Normal file
View File

@@ -0,0 +1,136 @@
package log
// Trace prints out logs on trace level
func (l gapLogger) Trace(args ...interface{}) {
l.subLogger.Print(args...)
}
// Formatted print for Trace
func (l gapLogger) Tracef(format string, args ...interface{}) {
l.subLogger.Printf(format, args...)
}
// Trace prints out logs on trace level with newline
func (l gapLogger) Traceln(args ...interface{}) {
l.subLogger.Println(args...)
}
// Debug prints out logs on debug level
func (l gapLogger) Debug(args ...interface{}) {
l.subLogger.Print(args...)
}
// Formatted print for Debug
func (l gapLogger) Debugf(format string, args ...interface{}) {
l.subLogger.Printf(format, args...)
}
// Formatted print for Debug
func (l gapLogger) Debugln(args ...interface{}) {
l.subLogger.Println(args...)
}
// Info prints out logs on info level
func (l gapLogger) Info(args ...interface{}) {
l.subLogger.Print(args...)
}
// Formatted print for Info
func (l gapLogger) Infof(format string, args ...interface{}) {
l.subLogger.Printf(format, args...)
}
// Info prints out logs on info level with newline
func (l gapLogger) Infoln(args ...interface{}) {
l.subLogger.Println(args...)
}
// Notice prints out logs on notice level
func (l gapLogger) Notice(args ...interface{}) {
l.subLogger.Print(args...)
}
// Formatted print for Notice
func (l gapLogger) Noticef(format string, args ...interface{}) {
l.subLogger.Printf(format, args...)
}
// Notice prints out logs on notice level with newline
func (l gapLogger) Noticeln(args ...interface{}) {
l.subLogger.Println(args...)
}
// Warn prints out logs on warn level
func (l gapLogger) Warn(args ...interface{}) {
l.subLogger.Print(args...)
}
// Formatted print for Warn
func (l gapLogger) Warnf(format string, args ...interface{}) {
l.subLogger.Printf(format, args...)
}
// Warn prints out logs on warn level with a newline
func (l gapLogger) Warnln(args ...interface{}) {
l.subLogger.Println(args...)
}
// Error prints out logs on error level
func (l gapLogger) Error(args ...interface{}) {
l.subLogger.Print(args...)
}
// Formatted print for error
func (l gapLogger) Errorf(format string, args ...interface{}) {
l.subLogger.Printf(format, args...)
}
// Error prints out logs on error level with a new line
func (l gapLogger) Errorln(args ...interface{}) {
l.subLogger.Println(args...)
}
// Panic prints out logs on panic level
func (l gapLogger) Panic(args ...interface{}) {
l.subLogger.Panic(args...)
}
// Formatted print for panic
func (l gapLogger) Panicf(format string, args ...interface{}) {
l.subLogger.Panicf(format, args...)
}
// Panic prints out logs on panic level with a newline
func (l gapLogger) Panicln(args ...interface{}) {
l.subLogger.Panicln(args...)
}
// Fatal prints out logs on fatal level
func (l gapLogger) Fatal(args ...interface{}) {
l.subLogger.Fatal(args...)
}
// Formatted print for fatal
func (l gapLogger) Fatalf(format string, args ...interface{}) {
l.subLogger.Fatalf(format, args...)
}
// Fatal prints fatal level with a new line
func (l gapLogger) Fatalln(args ...interface{}) {
l.subLogger.Fatalln(args...)
}
// Handles print to info
func (l gapLogger) Print(args ...interface{}) {
l.subLogger.Print(args...)
}
// Handles formatted print to info
func (l gapLogger) Printf(format string, args ...interface{}) {
l.subLogger.Printf(format, args...)
}
// Handles print to info with new line
func (l gapLogger) Println(args ...interface{}) {
l.subLogger.Println(args...)
}

View File

@@ -26,18 +26,12 @@ func init() {
} }
func (c *Client) logStdErr() { func (c *Client) logStdErr() {
for { for e := range c.writer {
select { if e.level >= c.LogLevel {
case e, more := <-c.writer: fmt.Fprintf(os.Stderr, "%s\t%s\t%s\t%s\n", e.Timestamp.String(), e.Level, e.Output, e.File)
if e.level >= c.LogLevel {
fmt.Fprintf(os.Stderr, "%s\t%s\t%s\t%s\n", e.Timestamp.String(), e.Level, e.Output, e.File)
}
if !more {
stderrFinished <- true
return
}
} }
} }
stderrFinished <- true
} }
func CreateClient() *Client { func CreateClient() *Client {
@@ -61,7 +55,7 @@ func Flush() {
func (c *Client) Destroy() error { func (c *Client) Destroy() error {
var otherClients []*Client var otherClients []*Client
if !c.initialized { if !c.initialized {
panic(errors.New("Cannot delete uninitialized client, did you use CreateClient?")) panic(errors.New("cannot delete uninitialized client, did you use CreateClient?"))
} }
sliceTex.Lock() sliceTex.Lock()
c.writer = nil c.writer = nil
@@ -78,7 +72,7 @@ func (c *Client) Destroy() error {
func (c *Client) GetLogLevel() Level { func (c *Client) GetLogLevel() Level {
if !c.initialized { if !c.initialized {
panic(errors.New("Cannot get level for uninitialized client, use CreateClient instead")) panic(errors.New("cannot get level for uninitialized client, use CreateClient instead"))
} }
return c.LogLevel return c.LogLevel
} }
@@ -109,14 +103,14 @@ func SetLogLevel(level Level) {
// SetLogLevel set log level of logger // SetLogLevel set log level of logger
func (c *Client) SetLogLevel(level Level) { func (c *Client) SetLogLevel(level Level) {
if !c.initialized { if !c.initialized {
panic(errors.New("Cannot set level for uninitialized client, use CreateClient instead")) panic(errors.New("cannot set level for uninitialized client, use CreateClient instead"))
} }
c.LogLevel = level c.LogLevel = level
} }
func (c *Client) Get() Entry { func (c *Client) Get() Entry {
if !c.initialized { if !c.initialized {
panic(errors.New("Cannot get logs for uninitialized client, did you use CreateClient?")) panic(errors.New("cannot get logs for uninitialized client, did you use CreateClient?"))
} }
return <-c.writer return <-c.writer
} }

View File

@@ -55,8 +55,7 @@ func BenchmarkDebugSerial(b *testing.B) {
// Trace ensure logs come out in the right order // Trace ensure logs come out in the right order
func TestOrder(t *testing.T) { func TestOrder(t *testing.T) {
testString := "Testing trace: " testString := "Testing trace: "
var c *Client c := CreateClient()
c = CreateClient()
c.SetLogLevel(LTrace) c.SetLogLevel(LTrace)
for i := 0; i < 5000; i++ { for i := 0; i < 5000; i++ {

View File

@@ -22,6 +22,9 @@ func (l Logger) Trace(args ...interface{}) {
level: LTrace, level: LTrace,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Trace(args...)
}
} }
// Formatted print for Trace // Formatted print for Trace
@@ -35,6 +38,9 @@ func (l Logger) Tracef(format string, args ...interface{}) {
level: LTrace, level: LTrace,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Tracef(format, args...)
}
} }
// Trace prints out logs on trace level with newline // Trace prints out logs on trace level with newline
@@ -48,6 +54,9 @@ func (l Logger) Traceln(args ...interface{}) {
level: LTrace, level: LTrace,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Traceln(args...)
}
} }
// Debug prints out logs on debug level // Debug prints out logs on debug level
@@ -61,6 +70,9 @@ func (l Logger) Debug(args ...interface{}) {
level: LDebug, level: LDebug,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Debug(args...)
}
} }
// Formatted print for Debug // Formatted print for Debug
@@ -74,6 +86,9 @@ func (l Logger) Debugf(format string, args ...interface{}) {
level: LDebug, level: LDebug,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Debugf(format, args...)
}
} }
// Info prints out logs on info level // Info prints out logs on info level
@@ -87,6 +102,9 @@ func (l Logger) Info(args ...interface{}) {
level: LInfo, level: LInfo,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Info(args...)
}
} }
// Formatted print for Info // Formatted print for Info
@@ -100,6 +118,9 @@ func (l Logger) Infof(format string, args ...interface{}) {
level: LInfo, level: LInfo,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Infof(format, args...)
}
} }
// Info prints out logs on info level with newline // Info prints out logs on info level with newline
@@ -113,6 +134,9 @@ func (l Logger) Infoln(args ...interface{}) {
level: LInfo, level: LInfo,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Infoln(args...)
}
} }
// Notice prints out logs on notice level // Notice prints out logs on notice level
@@ -126,6 +150,9 @@ func (l Logger) Notice(args ...interface{}) {
level: LNotice, level: LNotice,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Notice(args...)
}
} }
// Formatted print for Notice // Formatted print for Notice
@@ -139,6 +166,9 @@ func (l Logger) Noticef(format string, args ...interface{}) {
level: LNotice, level: LNotice,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Noticef(format, args...)
}
} }
// Notice prints out logs on notice level with newline // Notice prints out logs on notice level with newline
@@ -152,6 +182,9 @@ func (l Logger) Noticeln(args ...interface{}) {
level: LNotice, level: LNotice,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Noticeln(args...)
}
} }
// Warn prints out logs on warn level // Warn prints out logs on warn level
@@ -165,6 +198,9 @@ func (l Logger) Warn(args ...interface{}) {
level: LWarn, level: LWarn,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Warn(args...)
}
} }
// Formatted print for Warn // Formatted print for Warn
@@ -178,6 +214,9 @@ func (l Logger) Warnf(format string, args ...interface{}) {
level: LWarn, level: LWarn,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Warnf(format, args...)
}
} }
// Warn prints out logs on warn level with a newline // Warn prints out logs on warn level with a newline
@@ -191,6 +230,9 @@ func (l Logger) Warnln(args ...interface{}) {
level: LWarn, level: LWarn,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Warnln(args...)
}
} }
// Error prints out logs on error level // Error prints out logs on error level
@@ -204,6 +246,9 @@ func (l Logger) Error(args ...interface{}) {
level: LError, level: LError,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Error(args...)
}
} }
// Formatted print for error // Formatted print for error
@@ -217,6 +262,10 @@ func (l Logger) Errorf(format string, args ...interface{}) {
level: LError, level: LError,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Errorf(format, args...)
}
} }
// Error prints out logs on error level with a new line // Error prints out logs on error level with a new line
@@ -230,6 +279,9 @@ func (l Logger) Errorln(args ...interface{}) {
level: LError, level: LError,
} }
createLog(e) createLog(e)
for _, sl := range l.SubLoggers {
sl.Errorln(args...)
}
} }
// Panic prints out logs on panic level // Panic prints out logs on panic level
@@ -252,6 +304,9 @@ func (l Logger) Panic(args ...interface{}) {
} }
} }
Flush() Flush()
for _, sl := range l.SubLoggers {
sl.Panic(args...)
}
panic(errors.New(output)) panic(errors.New(output))
} }
@@ -275,6 +330,9 @@ func (l Logger) Panicf(format string, args ...interface{}) {
} }
} }
Flush() Flush()
for _, sl := range l.SubLoggers {
sl.Panicf(format, args...)
}
panic(errors.New(output)) panic(errors.New(output))
} }
@@ -298,6 +356,10 @@ func (l Logger) Panicln(args ...interface{}) {
} }
} }
Flush() Flush()
for _, sl := range l.SubLoggers {
sl.Panicln(args...)
}
panic(errors.New(output)) panic(errors.New(output))
} }
@@ -313,6 +375,9 @@ func (l Logger) Fatal(args ...interface{}) {
} }
createLog(e) createLog(e)
Flush() Flush()
for _, sl := range l.SubLoggers {
sl.Fatal(args...)
}
os.Exit(1) os.Exit(1)
} }
@@ -328,6 +393,9 @@ func (l Logger) Fatalf(format string, args ...interface{}) {
} }
createLog(e) createLog(e)
Flush() Flush()
for _, sl := range l.SubLoggers {
sl.Fatalf(format, args...)
}
os.Exit(1) os.Exit(1)
} }
@@ -343,20 +411,40 @@ func (l Logger) Fatalln(args ...interface{}) {
} }
createLog(e) createLog(e)
Flush() Flush()
for _, sl := range l.SubLoggers {
sl.Fatalln(args...)
}
os.Exit(1) os.Exit(1)
} }
// Handles print to info // Handles print to info
func (l Logger) Print(args ...interface{}) { func (l Logger) Print(args ...interface{}) {
l.Info(args...) l.Info(args...)
for _, sl := range l.SubLoggers {
sl.Print(args...)
}
} }
// Handles formatted print to info // Handles formatted print to info
func (l Logger) Printf(format string, args ...interface{}) { func (l Logger) Printf(format string, args ...interface{}) {
l.Infof(format, args...) l.Infof(format, args...)
for _, sl := range l.SubLoggers {
sl.Printf(format, args...)
}
} }
// Handles print to info with new line // Handles print to info with new line
func (l Logger) Println(args ...interface{}) { func (l Logger) Println(args ...interface{}) {
l.Infoln(args...) output := fmt.Sprintln(args...)
e := Entry{
Timestamp: time.Now(),
Output: output,
File: fileInfo(l.FileInfoDepth),
Level: "INFO",
level: LInfo,
}
createLog(e)
for _, sl := range l.SubLoggers {
sl.Println(args...)
}
} }

View File

@@ -2,8 +2,10 @@ package log
import "time" import "time"
type LogWriter chan Entry type (
type Level int LogWriter chan Entry
Level int
)
const ( const (
LTrace Level = iota LTrace Level = iota
@@ -30,6 +32,60 @@ type Entry struct {
level Level level Level
} }
func Default() *Logger {
l := Logger{FileInfoDepth: 0, SubLoggers: []LevelLogger{}}
return &l
}
func EnrichLogger(weak StdLogger) gapLogger {
return gapLogger{subLogger: weak}
}
type Logger struct { type Logger struct {
FileInfoDepth int FileInfoDepth int
SubLoggers []LevelLogger
} }
type gapLogger struct {
subLogger StdLogger
}
type (
StdLogger interface {
Println(v ...any)
Printf(format string, v ...any)
Print(v ...any)
Panic(v ...any)
Panicf(format string, v ...any)
Panicln(v ...any)
Fatal(v ...any)
Fatalf(format string, v ...any)
Fatalln(v ...any)
}
LevelLogger interface {
Debug(v ...any)
Debugf(format string, v ...any)
Error(v ...any)
Errorf(format string, v ...any)
Errorln(v ...any)
Fatal(v ...any)
Fatalf(format string, v ...any)
Fatalln(v ...any)
Info(v ...any)
Infof(format string, v ...any)
Infoln(v ...any)
Notice(v ...any)
Noticef(format string, v ...any)
Noticeln(v ...any)
Panic(v ...any)
Panicf(format string, v ...any)
Panicln(v ...any)
Print(v ...any)
Printf(format string, v ...any)
Println(v ...any)
Trace(v ...any)
Tracef(format string, v ...any)
Traceln(v ...any)
Warn(v ...any)
Warnf(format string, v ...any)
Warnln(v ...any)
}
)

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"flag" "flag"
"log"
"net/http" "net/http"
"time" "time"
@@ -29,5 +30,9 @@ func main() {
http.HandleFunc("/ws", ws.LogSocketHandler) http.HandleFunc("/ws", ws.LogSocketHandler)
http.HandleFunc("/", browser.LogSocketViewHandler) http.HandleFunc("/", browser.LogSocketViewHandler)
go generateLogs() go generateLogs()
dLogger := log.Default()
lsLogger := logger.Default()
lsLogger.SubLoggers = append(lsLogger.SubLoggers, logger.EnrichLogger(dLogger))
lsLogger.Println("This should be printed out twice!")
logger.Fatal(http.ListenAndServe(*addr, nil)) logger.Fatal(http.ListenAndServe(*addr, nil))
} }

View File

@@ -25,7 +25,7 @@ func LogSocketHandler(w http.ResponseWriter, r *http.Request) {
logger.Info("Websocket client attached.") logger.Info("Websocket client attached.")
for { for {
logEvent := lc.Get() logEvent := lc.Get()
logJSON, err := json.Marshal(logEvent) logJSON, _ := json.Marshal(logEvent)
err = c.WriteMessage(websocket.TextMessage, logJSON) err = c.WriteMessage(websocket.TextMessage, logJSON)
if err != nil { if err != nil {
logger.Error("write:", err) logger.Error("write:", err)