ZRY 1 month ago
parent
commit
027ba1ed43
8 changed files with 242 additions and 0 deletions
  1. 8 0
      .idea/.gitignore
  2. 9 0
      .idea/io_writer_to_logger.iml
  3. 7 0
      .idea/misc.xml
  4. 8 0
      .idea/modules.xml
  5. 6 0
      .idea/vcs.xml
  6. 1 0
      go.mod
  7. 50 0
      iowrlog.go
  8. 153 0
      iowrlog_test.go

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 9 - 0
.idea/io_writer_to_logger.iml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="Go" enabled="true" />
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 7 - 0
.idea/misc.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="XMakeProjectSettings">
+    <option name="currentArchitecture" value="x86" />
+    <option name="workingDirectory" value="$PROJECT_DIR$" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/io_writer_to_logger.iml" filepath="$PROJECT_DIR$/.idea/io_writer_to_logger.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>

+ 1 - 0
go.mod

@@ -0,0 +1 @@
+module git.swzry.com/zry/io_writer_to_logger

+ 50 - 0
iowrlog.go

@@ -0,0 +1,50 @@
+package io_writer_to_logger
+
+import (
+	"bufio"
+	"io"
+)
+
+type LogEmitFunc func(msg string)
+
+type WriterLogWrapper struct {
+	emitFunc   LogEmitFunc
+	pipeWriter *io.PipeWriter
+	pipeReader *io.PipeReader
+	scanner    *bufio.Scanner
+}
+
+func (w *WriterLogWrapper) Close() error {
+	err1 := w.pipeWriter.Close()
+	err2 := w.pipeReader.Close()
+	if err1 != nil {
+		return err1
+	}
+	if err2 != nil {
+		return err2
+	}
+	return nil
+}
+
+func NewWriterLogWrapper(emitFunc LogEmitFunc) *WriterLogWrapper {
+	pr, pw := io.Pipe()
+	return &WriterLogWrapper{
+		emitFunc:   emitFunc,
+		pipeWriter: pw,
+		pipeReader: pr,
+		scanner:    bufio.NewScanner(pr),
+	}
+}
+
+func (w WriterLogWrapper) Write(p []byte) (n int, err error) {
+	return w.pipeWriter.Write(p)
+}
+
+func (w WriterLogWrapper) Run() {
+	for w.scanner.Scan() {
+		t := w.scanner.Text()
+		w.emitFunc(t)
+	}
+}
+
+var _ io.WriteCloser = (*WriterLogWrapper)(nil)

+ 153 - 0
iowrlog_test.go

@@ -0,0 +1,153 @@
+package io_writer_to_logger
+
+import (
+	"fmt"
+	"io"
+	"strings"
+	"testing"
+	"time"
+)
+
+func TestLogger1(t *testing.T) {
+	tc := []string{
+		"hello",
+		"gensoukyo",
+		"satori",
+		"koishi",
+		"cirno",
+		"reimu",
+	}
+	lines := make([]string, 0)
+	lw := NewWriterLogWrapper(func(msg string) {
+		t.Log("[OUT] new line: ", msg)
+		lines = append(lines, msg)
+	})
+	waitCh := make(chan int)
+	go func() {
+		lw.Run()
+		waitCh <- 0
+	}()
+	t.Log("[LOG] writing...")
+	for _, v := range tc {
+		writeLineTest(t, lw, v)
+	}
+	t.Log("[LOG] closing...")
+	_ = lw.Close()
+	t.Log("[LOG] verifying...")
+	verifyStringArray(t, tc, lines)
+	t.Log("[LOG] wait for routine exit...")
+	<-waitCh
+	t.Log("[LOG] done.")
+}
+
+func writeLineTest(t *testing.T, w io.Writer, a ...interface{}) {
+	t.Log("[LOG] write line")
+	_, err := fmt.Fprintln(w, a...)
+	if err != nil {
+		t.Fatalf("[ERR] failed to write line: %v", err)
+	}
+}
+
+func writeTest(t *testing.T, w io.Writer, a ...interface{}) {
+	t.Log("[LOG] write")
+	_, err := fmt.Fprint(w, a...)
+	if err != nil {
+		t.Fatalf("[ERR] failed to write line: %v", err)
+	}
+}
+
+func verifyStringArray(t *testing.T, ref, data []string) {
+	if len(ref) != len(data) {
+		t.Fatalf("[ERR] len(ref) != len(data), ref: %d, data: %d", len(ref), len(data))
+	}
+	for i, v := range ref {
+		if v != data[i] {
+			t.Fatalf("[ERR] ref[%d] != data[%d], ref: %s, data: %s", i, i, ref, data)
+		}
+	}
+}
+
+func TestLogger2(t *testing.T) {
+	tc := [][]string{
+		{"hello"},
+		{"gensou", "kyo"},
+		{"sat", "ori"},
+		{"koishi"},
+		{"cirn", "o"},
+		{"r", "eimu"},
+	}
+	lines := make([]string, 0)
+	lw := NewWriterLogWrapper(func(msg string) {
+		t.Log("[OUT] new line: ", msg)
+		lines = append(lines, msg)
+	})
+	waitCh := make(chan int)
+	go func() {
+		lw.Run()
+		waitCh <- 0
+	}()
+	t.Log("[LOG] writing...")
+	for _, v1 := range tc {
+		l := len(v1)
+		for i, v2 := range v1 {
+			if i == l-1 {
+				writeLineTest(t, lw, v2)
+			} else {
+				writeTest(t, lw, v2)
+			}
+		}
+	}
+	t.Log("[LOG] closing...")
+	_ = lw.Close()
+	t.Log("[LOG] verifying...")
+	verifyString2DArray(t, tc, lines)
+	t.Log("[LOG] wait for routine exit...")
+	<-waitCh
+	t.Log("[LOG] done.")
+}
+
+func verifyString2DArray(t *testing.T, ref [][]string, data []string) {
+	if len(ref) != len(data) {
+		t.Fatalf("[ERR] len(ref) != len(data), ref: %d, data: %d", len(ref), len(data))
+	}
+	for i, v := range ref {
+		na := strings.Join(v, "")
+		if na != data[i] {
+			t.Fatalf("[ERR] ref[%d] != data[%d], ref: %s, data: %s", i, i, ref, data)
+		}
+	}
+}
+
+func TestLogger3(t *testing.T) {
+	verify := []string{
+		"hello",
+		"test",
+		"foo",
+		"bar",
+	}
+	lines := make([]string, 0)
+	lw := NewWriterLogWrapper(func(msg string) {
+		t.Log("[OUT] new line: ", msg)
+		lines = append(lines, msg)
+	})
+	waitCh := make(chan int)
+	go func() {
+		lw.Run()
+		waitCh <- 0
+	}()
+	t.Log("[LOG] writing...")
+	writeTest(t, lw, "hel")
+	writeLineTest(t, lw, "lo")
+	writeLineTest(t, lw, "test")
+	writeLineTest(t, lw, "foo")
+	writeTest(t, lw, "bar")
+	time.Sleep(time.Second)
+	t.Log("[LOG] closing...")
+	_ = lw.Close()
+	time.Sleep(time.Second)
+	t.Log("[LOG] verifying...")
+	verifyStringArray(t, verify, lines)
+	t.Log("[LOG] wait for routine exit...")
+	<-waitCh
+	t.Log("[LOG] done.")
+}