| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 | package logimport (	"fmt"	"io"	"log"	"net"	"os"	"path/filepath"	"strings"	"sync")const (	ServerMaxSize = 4194304 // 4MB)type ServerWriter struct {	Filepath string	W        map[string]io.Writer	Run      io.Writer	Err      io.Writer	mu sync.Mutex}// trim 移除 [] 中括号func (l *ServerWriter) trim(s string) string {	s = strings.TrimPrefix(s, "[")	s = strings.TrimSuffix(s, "[ ")	return s}func (l *ServerWriter) Write(p []byte) (n int, err error) {	level := string(p[:4])	if logs, ok := l.W[level]; ok {		return logs.Write(p)	}	switch level {	case PrefixDebug, PrefixInfo, PrefixWarning, PrefixError:		if level == PrefixWarning || level == PrefixError {			n, err = l.Err.Write(p)		}		n, err = l.Run.Write(p)	default:		w, err := NewWriter(l.trim(level), ".log", filepath.Join(l.Filepath, l.trim(level)))		if err == nil {			l.mu.Lock()			l.W[level] = w			l.mu.Unlock()			n, err = w.Write(p)		} else {			_, _ = os.Stdout.Write(p)		}	}	return}func NewServerWriter() *ServerWriter {	sw := new(ServerWriter)	sw.W = make(map[string]io.Writer)	return sw}type Server struct {	W    io.Writer	Conn net.PacketConn}func (c *Server) handle(b []byte) {	_, err := c.W.Write(b)	if err != nil {		_, _ = os.Stdout.Write(b)	}}func (c *Server) Close() error {	return c.Conn.Close()}func (c *Server) ListenAndServe() error {	defer func() {		_ = c.Close()	}()	for {		b := make([]byte, ServerMaxSize)		n, _, err := c.Conn.ReadFrom(b)		if err != nil {			log.Println("ReadFrom:", err)			continue		}		go c.handle(b[:n])	}}func NewServer(address, path string) (*Server, error) {	sw := NewServerWriter()	sw.Filepath = path	var err error	sw.Run, err = NewWriter("r", ".log", filepath.Join(path, "run"))	if err != nil {		return nil, err	}	sw.Err, err = NewWriter("e", ".log", filepath.Join(path, "err"))	if err != nil {		return nil, err	}	s := new(Server)	s.W = sw	s.Conn, err = net.ListenPacket("udp", address)	if err != nil {		return nil, err	}	return s, nil}type Client struct {	CallDepth int	Console   bool	conn      *net.UDPConn	debug     *log.Logger	info      *log.Logger	warning   *log.Logger	error     *log.Logger}func (c *Client) Close() error {	return c.conn.Close()}func (c *Client) Debug(f string, v ...any) {	_ = c.debug.Output(c.CallDepth, fmt.Sprintf(f, v...))}func (c *Client) Info(f string, v ...any) {	_ = c.info.Output(c.CallDepth, fmt.Sprintf(f, v...))}func (c *Client) Warning(f string, v ...any) {	_ = c.warning.Output(c.CallDepth, fmt.Sprintf(f, v...))}func (c *Client) Error(f string, v ...any) {	_ = c.error.Output(c.CallDepth, fmt.Sprintf(f, v...))}func NewClient(address string) (*Client, error) {	udpAddr, err := net.ResolveUDPAddr("udp", address)	if err != nil {		return nil, err	}	conn, err := net.DialUDP("udp", nil, udpAddr)	if err != nil {		return nil, err	}	c := new(Client)	c.conn = conn	c.debug = log.New(conn, PrefixDebug, Flag)	c.info = log.New(conn, PrefixInfo, Flag)	c.warning = log.New(conn, PrefixWarning, Flag)	c.error = log.New(conn, PrefixError, Flag)	return c, nil}
 |