package events import ( "strings" "sync" ) // LogLine — строка лога для панели «Логи». type LogLine struct { Level string Text string } func (LogLine) _event() {} // LogBus — тип-обёртка над *Bus для логов. // // Логи идут отдельной шиной, чтобы большие объёмы текста не блокировали // доменные события и наоборот. type LogBus struct { *Bus } // NewLogBus создаёт шину логов с буфером на подписчика. func NewLogBus(bufSize int) *LogBus { return &LogBus{Bus: New(bufSize)} } // LogWriter — io.Writer, который публикует каждую строку лога как LogLine. // Предполагается использование через log.SetOutput в связке, чтобы всё // логирование приложения попадало и в панель «Логи». type LogWriter struct { bus *Bus mu sync.Mutex // защищает остаток частичной строки buf strings.Builder } // NewLogWriter создаёт LogWriter, публикующий в шину логов события LogLine{Level:"log"}. func NewLogWriter(bus *LogBus) *LogWriter { return &LogWriter{bus: bus.Bus} } // Write реализует io.Writer. Данные разрезаются по переводам строки: // каждая законченная строка публикуется отдельным событием. func (w *LogWriter) Write(p []byte) (int, error) { w.mu.Lock() defer w.mu.Unlock() w.buf.Write(p) data := w.buf.String() for { idx := strings.IndexByte(data, '\n') if idx < 0 { break } line := strings.TrimSuffix(data[:idx], "\r") data = data[idx+1:] if line != "" { w.bus.Publish(LogLine{Level: "log", Text: line}) } } w.buf.Reset() w.buf.WriteString(data) return len(p), nil }