github.com/TeaOSLab/EdgeNode@v1.3.8/internal/nodes/http_access_log_viewer.go (about) 1 // Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . 2 3 package nodes 4 5 import ( 6 "fmt" 7 "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" 8 teaconst "github.com/TeaOSLab/EdgeNode/internal/const" 9 "github.com/TeaOSLab/EdgeNode/internal/remotelogs" 10 "github.com/iwind/TeaGo/types" 11 "net" 12 "os" 13 "sync" 14 "sync/atomic" 15 ) 16 17 var sharedHTTPAccessLogViewer = NewHTTPAccessLogViewer() 18 19 // HTTPAccessLogViewer 本地访问日志浏览器 20 type HTTPAccessLogViewer struct { 21 sockFile string 22 23 listener net.Listener 24 connMap map[int64]net.Conn // connId => net.Conn 25 connId int64 26 locker sync.Mutex 27 } 28 29 // NewHTTPAccessLogViewer 获取新对象 30 func NewHTTPAccessLogViewer() *HTTPAccessLogViewer { 31 return &HTTPAccessLogViewer{ 32 sockFile: os.TempDir() + "/" + teaconst.AccessLogSockName, 33 connMap: map[int64]net.Conn{}, 34 } 35 } 36 37 // Start 启动 38 func (this *HTTPAccessLogViewer) Start() error { 39 this.locker.Lock() 40 defer this.locker.Unlock() 41 42 if this.listener == nil { 43 // remove if exists 44 _ = os.Remove(this.sockFile) 45 46 // start listening 47 listener, err := net.Listen("unix", this.sockFile) 48 if err != nil { 49 return err 50 } 51 this.listener = listener 52 53 go func() { 54 for { 55 conn, err := this.listener.Accept() 56 if err != nil { 57 remotelogs.Error("ACCESS_LOG", "start local reading failed: "+err.Error()) 58 break 59 } 60 61 this.locker.Lock() 62 var connId = this.nextConnId() 63 this.connMap[connId] = conn 64 go func() { 65 this.startReading(conn, connId) 66 }() 67 this.locker.Unlock() 68 } 69 }() 70 } 71 72 return nil 73 } 74 75 // HasConns 检查是否有连接 76 func (this *HTTPAccessLogViewer) HasConns() bool { 77 this.locker.Lock() 78 defer this.locker.Unlock() 79 return len(this.connMap) > 0 80 } 81 82 // Send 发送日志 83 func (this *HTTPAccessLogViewer) Send(accessLog *pb.HTTPAccessLog) { 84 var conns = []net.Conn{} 85 this.locker.Lock() 86 for _, conn := range this.connMap { 87 conns = append(conns, conn) 88 } 89 this.locker.Unlock() 90 91 if len(conns) == 0 { 92 return 93 } 94 95 for _, conn := range conns { 96 // ignore error 97 _, _ = conn.Write([]byte(accessLog.RemoteAddr + " [" + accessLog.TimeLocal + "] \"" + accessLog.RequestMethod + " " + accessLog.Scheme + "://" + accessLog.Host + accessLog.RequestURI + " " + accessLog.Proto + "\" " + types.String(accessLog.Status) + " - " + fmt.Sprintf("%.2fms", accessLog.RequestTime*1000) + "\n")) 98 } 99 } 100 101 func (this *HTTPAccessLogViewer) nextConnId() int64 { 102 return atomic.AddInt64(&this.connId, 1) 103 } 104 105 func (this *HTTPAccessLogViewer) startReading(conn net.Conn, connId int64) { 106 var buf = make([]byte, 1024) 107 for { 108 _, err := conn.Read(buf) 109 if err != nil { 110 this.locker.Lock() 111 delete(this.connMap, connId) 112 this.locker.Unlock() 113 break 114 } 115 } 116 }