-
Notifications
You must be signed in to change notification settings - Fork 18.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
service logs #28089
service logs #28089
Conversation
if err != nil { | ||
return 0, err | ||
} | ||
if n != len(output) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Write must return a non-nil error if it returns n < len(p)
If lw.w.Write
follows this requirement, this check should not be necessary.
return 0, err | ||
} | ||
if n != len(output) { | ||
return 0, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted above, this if
doesn't seem necessary. But if it's kept, it should return n
and a non-nil error.
} | ||
query.Set("tail", options.Tail) | ||
|
||
resp, err := cli.get(ctx, "/services/"+serviceID+"/logs", query, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if we should validate client-side that user input only contains valid characters. Passing in a service ID with a ?
in it will cause some pretty weird behavior. But this should probably be done in a different PR.
msg.Context.NodeID, | ||
msg.Context.ServiceID, | ||
msg.Context.TaskID, | ||
)), data...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would reorder these appends
to append rather than prepend. This is more intuitive and also slightly more efficient (prepending has to copy the old contents, appending might not if cap(x) > len(x)
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it might be more efficient to just flush to the stream, rather than assembling the entire data buffer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Followed the same pattern as docker logs
(reverse append) - I can change that
|
||
serviceName := vars["id"] | ||
logsConfig := &backend.ContainerLogsConfig{ | ||
ContainerLogsOptions: basictypes.ContainerLogsOptions{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we rename this to LogsOptions
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a follow up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a TODO somewhere?
@aaronlehmann @stevvooe Actually, the biggest thing I need to solve is the format. Here's docker logs:
Details ( In
Having the context in details makes the service logs protocol 100% compliant with Thoughts? /cc @tiborvass @icecrime @vieux
|
@aluzzardi I would start by the timestamp, so I vote for |
I vote for 3. |
Which one though:
@dnephin @aanand Any input? The output of @stevvooe @vieux The weird part is that context has a special meaning. The CLI will parse out the context to resolve it (map service ID to names and so on) |
I'm in favor of this, since you need the context to disambiguate the streams. |
@aluzzardi #28088 was merged |
@@ -17,6 +19,7 @@ type Backend interface { | |||
CreateService(types.ServiceSpec, string) (string, error) | |||
UpdateService(string, uint64, types.ServiceSpec, string, string) error | |||
RemoveService(string) error | |||
ServiceLogs(context.Context, string, *backend.ContainerLogsConfig, chan struct{}) error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be better to follow Verb + Noun naming convention. ServiceLogs
-> GetServiceLogs
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Staying consistent with ContainerLogs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be better to follow Verb + Noun naming convention.
This is not a convention in Go.
} | ||
|
||
func (lw *logWriter) Write(buf []byte) (int, error) { | ||
parts := bytes.SplitN(buf, []byte(" "), 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean context cannot have any space?
noResolve bool | ||
follow bool | ||
since string | ||
timestamps bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does logs from different nodes ordered by timestamps by default? As an option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. The resource requirements for doing so are too intensive. In practice, they tend to come in with the correct ordering. To guarantee it, you have to buffer all logs, sort them and merge on client-side. Empty signals also need to be sent to preserve ordering.
Keep in mind that this means:
Are we cool with that, @stevvooe @aaronlehmann @vieux @icecrime ? |
I think the logs are going to be pretty confusing without the task id. I would opt for always including a task id by default (maybe a flag to disable it). |
Stop gaps: non-follow is not supported, details is not supported |
@aluzzardi I get
|
context[parts[0]] = parts[1] | ||
} | ||
|
||
taskID, ok := context["task_id"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use the convention of task.id
we've used in labels. It might also be a good idea to namespace these com.docker.swarm
.
@vieux Yeah, unfortunately, only follow mode ( |
my bad @aluzzardi I read |
neat 👍
|
LGTM I think we can tweak the output quite a bit but let's do that in a follow up. |
@@ -1121,6 +1130,82 @@ func (c *Cluster) RemoveService(input string) error { | |||
return nil | |||
} | |||
|
|||
// ServiceLogs collects service logs and writes them back to `config.OutStream` | |||
func (c *Cluster) ServiceLogs(ctx context.Context, input string, config *backend.ContainerLogsConfig, started chan struct{}) error { | |||
if !c.isActiveManager() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to get a readlock for this. You can release it before the long running operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. PTAL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
It would be nice to get it for 1.13, but since it's still missing a few feature and after some discussion among the engine maintainers, we think it's best if you can put this in experimental only @al |
Plumbed the executor to the container logs backend. Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
Moved to experimental @vieux PTAL |
LGTM |
Hi, I tried this feature in my staging swarm cluster and it didn't worked as expected. I reproduced the error here: http://play-with-docker.com/p/f0020045-d8e8-4bf0-a86c-55f3a25cd4dd I left some messages related with this in the swam slack room. If you want me to create an issue just tell it to me. |
@bvis: I wasn't able to load your link. I get the error message "session not found". Opening an issue with some details sounds like a good next step. |
@aaronlehmann Here you are: #28915 |
service logs
This PR adds
docker service logs
support by wiring up the SwarmKit logs plumbing.This includes:
docker logs
docker service logs
I want to validate the API before documenting and adding integration tests, so this PR does not include them and is not in a mergeable state.
/cc @aaronlehmann @stevvooe