Repository: linuxkit/linuxkit (language: go)

Issue:
logread v1.0 does not "-F"ollow 
**Description**

logread in memlogd v1.0.0 does not appear to "-F"ollow (but will "-f"ollow) a given memlogd instance

**Steps to reproduce the issue:**

Consider the following dockerfile

```dockerfile
FROM linuxkit/memlogd:v0.8-amd64 AS memlogd-0.8
FROM linuxkit/memlogd:v1.0.0-amd64 AS memlogd-1.0

FROM alpine:3.19    

COPY --from=memlogd-1.0 /usr/bin/memlogd /usr/bin/memlogd
COPY --from=memlogd-0.8 /usr/bin/logread /usr/bin/logread-0.8
COPY --from=memlogd-1.0 /usr/bin/logread /usr/bin/logread-1.0
```

build it, run it in interactive, run the following:

```shell
memlogd &

logread-0.8 -F
logread-1.0 -F
```


**Describe the results you received:**
```
/ # memlogd &
...
/ # logread-0.8  -F
{"time":"2024-07-02T19:22:51.974497577Z","source":"memlogd","msg":"memlogd started"}
^C
/ # logread-1.0  -F
2024-07-02T19:22:51.974497577Z;memlogd;memlogd started
/ # 
```

**Describe the results you expected:**

note in the -0.8 version i had to ctrl c out - as expected the instance of logread was "-F"ollowing the memlogd logs
note in the 1.0 version i was returned to the command line  straight away - there was no "-F"ollow behaviour

**Additional information you deem important (e.g. issue happens only occasionally):**

maybe a different issue - the json log line is confusing me slightly: i thought this was supposed to be a custom ';'-separated format, as seen in the v1.0 logread? im happy if this is a thing as its more useful to my purposes. i had a check of the images with [dive](https://github.com/wagoodman/dive) and theres nothing else named logread (like, e.g. [busyboxes logread](https://boxmatrix.info/wiki/Property:logread)) that i could be mistakenly copying out there.

few other basic diagnostics:

```shell
/ # logread-0.8 -v
flag provided but not defined: -v
Usage of logread-0.8:
  -F	dump log, then follow
  -f	follow log buffer
  -socket string
    	memlogd log query socket (default "/var/run/memlogdq.sock")
/ # logread-1.0 -v
flag provided but not defined: -v
Usage of logread-1.0:
  -F	dump log, then follow
  -f	follow log buffer
  -socket string
    	memlogd log query socket (default "/var/run/memlogdq.sock")
/ # ls -lah $(which logread-0.8) $(which logread-1.0)
-rwxr-xr-x    1 root     root        2.5M May 10  2020 /usr/bin/logread-0.8
-rwxr-xr-x    1 root     root        1.8M Jan 28 19:40 /usr/bin/logread-1.0
```




Discussion / hints:
Looks like the issue is [here](https://github.com/linuxkit/linuxkit/blob/master/pkg/memlogd/cmd/logread/main.go#L44):

```go
	c, err := StreamLogs(socketPath, follow, dumpFollow)
```

The first arg is the socketPath, makes sense. The second is `follow bool` and the third is `dumpFollow bool`. But the signature is slightly different:

```go
func StreamLogs(socketPath string, follow, dump bool) (<-chan LogEntry, error)
```

Meaning whether or not to follow is second arg, and whether or not to dump is third arg. That combination of dump OR follow OR "dump and follow" should be resolved in the command handler before calling `StreamLogs`. I suspect it should be something like:

```go
	flag.StringVar(&socketPath, "socket", "/var/run/memlogdq.sock", "memlogd log query socket")
	flag.BoolVar(&dumpFollow, "F", false, "dump log, then follow")
	flag.BoolVar(&follow, "f", false, "follow log buffer")
	flag.Parse()

	if dumpFollow {
		follow = true
	}

	c, err := StreamLogs(socketPath, follow, dumpFollow)
```

Test it yourself and, if it works, open a PR?
That appears to have solved the issue :)

```shell
git clone git@github.com:linuxkit/linuxkit.git
cd linuxkit/pkg/memlogd
nano cmd/logread/main.go
# make the above edit
docker build -t logreadedit .
```

the test dockerfile now reads:
```dockerfile
FROM linuxkit/memlogd:v0.8-amd64 AS memlogd-0.8
FROM linuxkit/memlogd:v1.0.0-amd64 AS memlogd-1.0
FROM logreadedit AS memlogd-edit

FROM alpine:3.19    

COPY --from=memlogd-1.0 /usr/bin/memlogd /usr/bin/memlogd
COPY --from=memlogd-0.8 /usr/bin/logread /usr/bin/logread-0.8
COPY --from=memlogd-1.0 /usr/bin/logread /usr/bin/logread-1.0
COPY --from=memlogd-edit /usr/bin/logread /usr/bin/logread-edit
```

and repeating the above tests (including extra case for newest build)

```shell
/ # memlogd &
...
/ # logread-0.8 -F
{"time":"2024-07-03T12:28:54.983065534Z","source":"memlogd","msg":"memlogd started"}
^C
/ # logread-1.0 -F
2024-07-03T12:28:54.983065534Z;memlogd;memlogd started
/ # logread-edit -F
2024-07-03T12:28:54.983065534Z;memlogd;memlogd started
^C
```

Will get a PR together Soon(tm)
incidentally do you have any comment about the different formatting between the 0.8 and 1.0 builds of logread? 

at a brief perusal of [commits to memlogd/logread between 0.8 and 1.0](https://github.com/linuxkit/linuxkit/commit/0b136bf80d995f7ee3571a5347d890e705f48fb5) indicates  its due to memlogd-1.0 changing to sending json serialised logs - with logread-0.8 just dumping all text and logread-1.0 actually parsing the incoming json. do you concur with this? If so I'll probably open a small issue+pr to add a --json (or similar) flag as dumping the raw json would be really useful to me.


[This](https://github.com/linuxkit/linuxkit/pull/3807) is the PR for that, about 2 years ago. This changes the format to be json and thus more standardized.

If you are looking for a way to have `logread` have alternative output formats, I don't see why not. As long as the default behaivour is unchanged, it should be fine.

Fix patch:
diff --git a/pkg/memlogd/cmd/logread/main.go b/pkg/memlogd/cmd/logread/main.go
index 78571971b1..2e091f8e2a 100644
--- a/pkg/memlogd/cmd/logread/main.go
+++ b/pkg/memlogd/cmd/logread/main.go
@@ -41,6 +41,11 @@ func main() {
 	flag.BoolVar(&follow, "f", false, "follow log buffer")
 	flag.Parse()
 
+	if dumpFollow {
+		// StreamLogs() has seperate 'dump' and 'follow' flags, since 'dumpFollow' includes 'follow' we set that too
+		follow = true
+	}
+
 	c, err := StreamLogs(socketPath, follow, dumpFollow)
 	if err != nil {
 		panic(err)


Test patch: