diff --git a/cmd/syncthing/monitor.go b/cmd/syncthing/monitor.go
index af64be32..d48b4506 100644
--- a/cmd/syncthing/monitor.go
+++ b/cmd/syncthing/monitor.go
@@ -22,10 +22,13 @@ import (
"os/exec"
"os/signal"
"path/filepath"
+ "runtime"
"strings"
"sync"
"syscall"
"time"
+
+ "github.com/syncthing/syncthing/internal/osutil"
)
var (
@@ -45,16 +48,29 @@ func monitorMain() {
l.SetPrefix("[monitor] ")
var err error
- var dst io.Writer
+ var dst io.Writer = os.Stdout
- if logFile == "" {
- dst = os.Stdout
- } else {
- dst, err = os.Create(logFile)
+ if logFile != "" {
+ var fileDst io.Writer
+
+ fileDst, err = os.Create(logFile)
if err != nil {
l.Fatalln("log file:", err)
}
- l.Infof(`Log output directed to file "%s"`, logFile)
+
+ if runtime.GOOS == "windows" {
+ // Translate line breaks to Windows standard
+ fileDst = osutil.ReplacingWriter{
+ Writer: fileDst,
+ From: '\n',
+ To: []byte{'\r', '\n'},
+ }
+ }
+
+ // Log to both stdout and file.
+ dst = io.MultiWriter(dst, fileDst)
+
+ l.Infof(`Log output saved to file "%s"`, logFile)
}
args := os.Args
diff --git a/internal/osutil/replacingwriter.go b/internal/osutil/replacingwriter.go
new file mode 100644
index 00000000..4eac5908
--- /dev/null
+++ b/internal/osutil/replacingwriter.go
@@ -0,0 +1,57 @@
+// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see .
+
+package osutil
+
+import (
+ "bytes"
+ "io"
+)
+
+type ReplacingWriter struct {
+ Writer io.Writer
+ From byte
+ To []byte
+}
+
+func (w ReplacingWriter) Write(bs []byte) (int, error) {
+ var n, written int
+ var err error
+
+ newlineIdx := bytes.IndexByte(bs, w.From)
+ for newlineIdx >= 0 {
+ n, err = w.Writer.Write(bs[:newlineIdx])
+ written += n
+ if err != nil {
+ break
+ }
+ if len(w.To) > 0 {
+ n, err := w.Writer.Write(w.To)
+ if n == len(w.To) {
+ written++
+ }
+ if err != nil {
+ break
+ }
+ }
+ bs = bs[newlineIdx+1:]
+ newlineIdx = bytes.IndexByte(bs, w.From)
+ }
+
+ n, err = w.Writer.Write(bs)
+ written += n
+
+ return written, err
+}
diff --git a/internal/osutil/replacingwriter_test.go b/internal/osutil/replacingwriter_test.go
new file mode 100644
index 00000000..c2332063
--- /dev/null
+++ b/internal/osutil/replacingwriter_test.go
@@ -0,0 +1,53 @@
+// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see .
+
+package osutil
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+)
+
+var testcases = []struct {
+ from byte
+ to []byte
+ a, b string
+}{
+ {'\n', []byte{'\r', '\n'}, "", ""},
+ {'\n', []byte{'\r', '\n'}, "foo", "foo"},
+ {'\n', []byte{'\r', '\n'}, "foo\n", "foo\r\n"},
+ {'\n', []byte{'\r', '\n'}, "foo\nbar", "foo\r\nbar"},
+ {'\n', []byte{'\r', '\n'}, "foo\nbar\nbaz", "foo\r\nbar\r\nbaz"},
+ {'\n', []byte{'\r', '\n'}, "\nbar", "\r\nbar"},
+ {'o', []byte{'x', 'l', 'r'}, "\nfoo", "\nfxlrxlr"},
+ {'o', nil, "\nfoo", "\nf"},
+ {'f', []byte{}, "\nfoo", "\noo"},
+}
+
+func TestReplacingWriter(t *testing.T) {
+ for _, tc := range testcases {
+ var buf bytes.Buffer
+ w := ReplacingWriter{
+ Writer: &buf,
+ From: tc.from,
+ To: tc.to,
+ }
+ fmt.Fprint(w, tc.a)
+ if buf.String() != tc.b {
+ t.Errorf("%q != %q", buf.String(), tc.b)
+ }
+ }
+}