X Tutup
Skip to content

Implement plugins for logging drivers#28403

Merged
thaJeztah merged 1 commit intomoby:masterfrom
cpuguy83:logging_plugins
Apr 10, 2017
Merged

Implement plugins for logging drivers#28403
thaJeztah merged 1 commit intomoby:masterfrom
cpuguy83:logging_plugins

Conversation

@cpuguy83
Copy link
Member

This is intended as PoC code that as of yet untested other than ensuring compilation.

Logging plugins use the same HTTP interface as other plugins for basic
command operations meanwhile actual logging operations are handled (on
Unix) via a fifo. I believe this is much cleaner than dealing with go1.8 style plugins.

The plugin interface looks like so:

type loggingPlugin interface {
  StartLogging(fifoPath string, loggingContext Context) error
  StopLogging(fifoPath)
}

This means a plugin must implement LoggingDriver.StartLogging and
LoggingDriver.StopLogging endpoints and be able to consume the passed
in fifo.

Logs are sent via stream encoder to the fifo encoded with json.
Ideally this would be protobuf, but I did not implement this yet.

ping @tiborvass @anusha-ragunathan

@cpuguy83
Copy link
Member Author

The other alternative here would be to, instead of using fifo's, either hijack the HTTP stream (getting rid of the HTTP overhead), or potentially force an upgrade to HTTP2 (which is likely simpler for implementers than hijack).

@tianon
Copy link
Member

tianon commented Nov 17, 2016

Just to note for those looking for something in the interim, Docker does currently support GELF (which is a standardized protocol for logging), so anything which can consume that (and/or translate that, like logstash input/output plugins) can be connected currently that way while a proper plugin interface is designed/developed. 👍

@AkihiroSuda
Copy link
Member

Thank you for working on this 👍

Some questions about FIFO, from my previous similar PR (#23198)

  • What happens if the plugin doesn't read(2) from the FIFO? Probably the container gets stuck because its write(2) to stdout blocks?
  • What happens if the plugin crashes?

@cpuguy83
Copy link
Member Author

cpuguy83 commented Nov 22, 2016

What happens if the plugin doesn't read(2) from the FIFO? Probably the container gets stuck because its write(2) to stdout blocks?

Correct, write will be blocked, which is the behavior for all existing drivers except UDP based ones.

What happens if the plugin crashes?

writes will be blocked until the plugin comes back

@cpuguy83
Copy link
Member Author

@AkihiroSuda For non-blocking behavior, I implemented a ring buffer that can be used with any driver in #28762

@cpuguy83
Copy link
Member Author

Since we are already going to be communicating over a unix socket, I'm going to ditch the fifo. These offer similar performance, but with the unix socket I don't have to setup anything else.

@cpuguy83
Copy link
Member Author

cpuguy83 commented Jan 2, 2017

Just an update on this:

  • writing logs works
  • Kept usage of fifo since it is actually much simpler than dealing with the http connection, can support named pipes on Windows later when there is platform support for this
  • Reading logs is supported if the log driver reports that it supports reading

To think about (need input from others):

  1. Should we just use a single stream for all log messages (from all containers) to the log driver? This would require encoding the log context with each message (easy enough). This would likely simplify plugin implementations, but make the docker side a bit more complex.
  2. Do we need some cleanup call for log drivers? I'm thinking likely not but throwing it out there. As is I have a plugin which wraps the jsonfile driver which would need a way cleanup logs for removed containers... but I think this is just because of the nature of the jsonfile logger, a real log driver wouldn't just remove logs in this manner.

Here's my plugin implementation: https://github.com/cpuguy83/docker-log-driver-test
I do have a (simple) integration test that uses this driver to both write and read back container logs.

@cpuguy83
Copy link
Member Author

cpuguy83 commented Apr 8, 2017

This should be good to go.

@anusha-ragunathan
Copy link
Contributor

docs/extend/config.md has the list of drivers currently supported. It needs to be updated.

@cpuguy83
Copy link
Member Author

Added.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this call to io.ReadFull necessary, given the real read at L 83?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this gets the size of the message.
83 gets the actual message, which we need the size of to know where it ends.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldnt uint32(n) -> uint32(total) ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are putting writing the size of the log entry to the buffer.
But the buffer needs to be the total size otherwise we'll be 4-bytes short.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I just looked at the logEntry's Size() implementation. Looks good.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TimeNano is not copied into the dAtA marshal output. Looks incorrect.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is an protobuf optimization since TimeNano is an int64 already there is nothing extra to copy.

Copy link

@tgermain tgermain Apr 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo, josn should be json I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

josn, it's the same as json, but all the keys are scrambled up.

:) Thanks I do this all the time.

Logging plugins use the same HTTP interface as other plugins for basic
command operations meanwhile actual logging operations are handled (on
Unix) via a fifo.

The plugin interface looks like so:

```go
type loggingPlugin interface {
  StartLogging(fifoPath string, loggingContext Context) error
  StopLogging(fifoPath)
```

This means a plugin must implement `LoggingDriver.StartLogging` and
`LoggingDriver.StopLogging` endpoints and be able to consume the passed
in fifo.

Logs are sent via stream encoder to the fifo encoded with protobuf.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
@anusha-ragunathan
Copy link
Contributor

@cpuguy83: I'm okay with a follow up PR to address

@anusha-ragunathan
Copy link
Contributor

LGTM

@cpuguy83
Copy link
Member Author

Cool, going to move to docs-review then, thanks!

@thaJeztah
Copy link
Member

Discussed with @cpuguy83 and we'll do a follow up for docs due to code-freeze today

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X Tutup