Skip to content

Improve partial message support in logger - #35831

Merged
anusha-ragunathan merged 1 commit into
moby:masterfrom
anusha-ragunathan:splunk_partial
Apr 13, 2018
Merged

anusha-ragunathan merged 1 commit into
moby:masterfrom
anusha-ragunathan:splunk_partial

Conversation

@anusha-ragunathan

@anusha-ragunathan anusha-ragunathan commented Dec 19, 2017 •

Copy link
Copy Markdown
Contributor

Improve partial message support in logger and use it in Splunk.

Docker daemon has a 16K buffer for log messages. If a message length
exceeds 16K, it should be split by the logger and merged at the
endpoint.

This change adds LogMetaData struct for enhanced partial support
IsPartial (bool) : Indicates if this message is partial
LastPartial (bool) : indicates if this is the last of all partials.
ID (string) : unique 32 bit ID. ID is same across all partials.
Ordinal (int starts at 1) : indicates the position of msg in the series of partials.

Signed-off-by: Anusha Ragunathan anusha.ragunathan@docker.com

@cpuguy83

Copy link
Copy Markdown
Member

daemon/logger/splunk/splunk.go:123::error: struct field tag json: "partial,omitempty" not compatible with reflect.StructTag.Get: bad syntax for struct tag value (vet)

Comment thread daemon/logger/splunk/splunk.go Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah, yes the space after json: should be removed

@anusha-ragunathan

Copy link
Copy Markdown
Contributor Author

powerpc and z tests failures due to #35775

@cpuguy83 cpuguy83 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@cpuguy83

cpuguy83 commented Dec 21, 2017 •

Copy link
Copy Markdown
Member

@thaJeztah Who do we know from splunk to review this?

@thaJeztah

Copy link
Copy Markdown
Member

@outcoldman and @glennblock worked on the logging driver previously, but don't think they're still working for Splunk (but perhaps they know who to contact), and I saw @michaelwilde comment on one of the pull requests (he looks to be still with Splunk, so 👍)

@thaJeztah

Copy link
Copy Markdown
Member

oh! saw https://github.com/splunk/docker-logging-plugin, so YOLO let me spam @bbourbie and @hyfather 😇

@outcoldman

Copy link
Copy Markdown
Contributor

Also @mchene can find somebody for review.

Btw, I believe HTTP Event Collector will just ignore Partial field in the event, see REST endpoint definition http://docs.splunk.com/Documentation/Splunk/7.0.1/RESTREF/RESTinput#services.2Fcollector

@hyfather

hyfather commented Jan 2, 2018

Copy link
Copy Markdown

Sorry just looking at this, was OOO -- hope everyone had a great holiday! 🎉

Each HTTP request to Splunk is treated separately, so there needs to be a unique identifier across all partial requests that docker sends so that Splunk can tell which lines need to be merged into a single event. Note that the Splunk endpoint that docker is making requests to could also be a load balancer and multiple HTTP requests carrying a partial line could be send to separate Splunk indexing servers.

Getting a little Splunk specific here -- even if we change the plugin to add a line merging token to the first of the partial request to use the SHOULD_LINEMERGE & BREAK_ONLY_BEFORE directives there is no guarantee that two partial requests will hit the same indexer. Any ideas on how to solve for this using props.conf?

As far as sending partial with each request, looks like HEC doesn't like it for a default JSON style payload --

$ curl -d '{"event": {"foo": "bar"}}' http://localhost:8088/services/collector?channel=20337e7a-eb6e-46f4-94a8-926b90e11bc5 -H 'Authorization: Splunk 20337e7a-eb6e-46f4-94a8-926b90e11bc5'
=> {"text":"Success","code":0,"ackId":0}


$ curl -d '{"partial": false, "event": {"foo": "bar"}}' http://localhost:8088/services/collector?channel=20337e7a-eb6e-46f4-94a8-926b90e11bc5 -H 'Authorization: Splunk 20337e7a-eb6e-46f4-94a8-926b90e11bc5'
=> {"text":"No data","code":5}

@outcoldman

Copy link
Copy Markdown
Contributor

@hyfather I am confused, looking on the documentation http://docs.splunk.com/Documentation/Splunk/7.0.1/RESTREF/RESTinput#services.2Fcollector, does not seem like HTTP Event Collector supports partial field. If this is a new, additional feature, is it going to be documented? Also if this is a new feature in 7.x, I assume that will not work with Splunk versions below 7?

@hyfather

hyfather commented Jan 2, 2018

Copy link
Copy Markdown

@outcoldman partial isn't a field on the HEC. It is this PR that adds partial to the outbound HTTP request. Maybe I got the structure of how it'll be marshaled wrong?

@cpuguy83

cpuguy83 commented Jan 2, 2018 •

Copy link
Copy Markdown
Member

Maybe some missing context here, but I believe Docker Inc has been working with Splunk to get some kind of support added for this scenario (single line broken into multiple events due to huge lines) so that the moby splunk driver can deal with it properly.

@hyfather

hyfather commented Jan 2, 2018

Copy link
Copy Markdown

@cpuguy83 got it! I wasn't aware of this -- it's probably best to wait for @mchene to weigh in. Thanks!

@boaz0 boaz0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM 👍

@anusha-ragunathan

Copy link
Copy Markdown
Contributor Author

Looks like without unique ID attached to messages, this PR would not be useful for Splunk. So lets not merge this yet.

@hyfather: Adding a unique 32 bit string ID to the messages can be done alongside partial log detection. Diff on top of this PR: https://gist.github.com/anusha-ragunathan/214b5c93ee89cb8342d101ada0f8bc63
Would that work?

@anusha-ragunathan

anusha-ragunathan commented Jan 6, 2018 •

Copy link
Copy Markdown
Contributor Author

Failures on ppc and experimental due to #35914
https://jenkins.dockerproject.org/job/Docker-PRs-powerpc/7746/consoleText

=== RUN   TestDaemonRestartKillContainers/live-restore=true/container_with_restart=always/stop-daemon
--- FAIL: TestDaemonRestartKillContainers (0.00s)
    --- PASS: TestDaemonRestartKillContainers/live-restore=true/container_with_restart=always/kill-daemon (2.20s)
    	daemon.go:285: [dc7f9929f10b5] waiting for daemon to start
    	daemon.go:317: [dc7f9929f10b5] daemon started
    	daemon.go:285: [dc7f9929f10b5] waiting for daemon to start
    	daemon.go:317: [dc7f9929f10b5] daemon started
    	daemon.go:275: [dc7f9929f10b5] exiting daemon
    --- FAIL: TestDaemonRestartKillContainers/live-restore=false/container_with_restart=always/kill-daemon (2.37s)
    	daemon.go:285: [df3331f4626eb] waiting for daemon to start
    	daemon.go:285: [df3331f4626eb] waiting for daemon to start
    	daemon.go:285: [df3331f4626eb] waiting for daemon to start
    	daemon.go:275: [df3331f4626eb] exiting daemon
    	daemon.go:203: Error starting daemon with arguments: []
    --- FAIL: TestDaemonRestartKillContainers/live-restore=false/container_with_restart=always/stop-daemon (0.31s)
    	daemon.go:285: [d66d385ff1cb0] waiting for daemon to start
    	daemon.go:275: [d66d385ff1cb0] exiting daemon
    	daemon.go:203: Error starting daemon with arguments: []

@anusha-ragunathan

Copy link
Copy Markdown
Contributor Author

@cpuguy83 @thaJeztah @outcoldman @hyfather @ripcurld0 I've updated the PR to include a unique PartialID for partial messages so that they can be assembled by Splunk. PTAL.

@cpuguy83

cpuguy83 commented Jan 9, 2018

Copy link
Copy Markdown
Member

I think for this to work we'd need a message ID which span across multiple partials and then an ordinal for each partial.

@anusha-ragunathan

Copy link
Copy Markdown
Contributor Author

My bad. Right now, msg.reset will reset the PartialID on each partial Log. Let me fix that and add a sequence number to the partial messages.
The problem of partials getting directed to different indexing servers still remain.

@hyfather

hyfather commented Jan 9, 2018

Copy link
Copy Markdown

@cpuguy83, @anusha-ragunathan -- yes a PartialID with an ordinal makes the most sense, along with the first partial indicating the total pieces to expect (is this possible?). This should be sufficient information for any aggregation service to assemble events or discard incomplete ones.
In addition, I'll follow up internally @ Splunk to see who is working on the receiving piece.

@cpuguy83

cpuguy83 commented Jan 9, 2018

Copy link
Copy Markdown
Member

I don't think we can send along the number to expect, which indeed would be nice, unless we cache all the messages locally first, this would in turn bring us back to square one with the size of these log messages.

@anusha-ragunathan
anusha-ragunathan force-pushed the splunk_partial branch 3 times, most recently from 5ada877 to 0db73b5 Compare April 5, 2018 18:20
@cpuguy83

cpuguy83 commented Apr 5, 2018 via email

Copy link
Copy Markdown
Member

@cpuguy83 cpuguy83 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Wondering if the message timestamp for partials should all be the same?

@anusha-ragunathan

Copy link
Copy Markdown
Contributor Author

@cpuguy83 : Theoretically, they should be. But it doesnt serve any real purpose.

@thaJeztah

Copy link
Copy Markdown
Member

Keep in mind that generating an ID is not free.

Fair point. Still a bit on the fence for "partials" starting with ordinal 1, and "full" messages having ordinal 0 (#35831 (comment))

Wondering if the message timestamp for partials should all be the same?

We're already using some state variables for partial messages; perhaps adding one for timestamp would work to address that? (even if it's theoretical, it would be "correct")

@anusha-ragunathan

Copy link
Copy Markdown
Contributor Author

@thaJeztah : I'll change the struct to a pointer to struct. That way, its nil for Full entries and avoids any confusion.

@anusha-ragunathan

Copy link
Copy Markdown
Contributor Author

@cpuguy83 : Updated PR to have same timestamp for all partials
@thaJeztah : Updated PR to have PartialLogMetaData only for partials. Full log entries have a nil pointer.

PTAL.

Comment thread daemon/logger/copier.go Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we keep a PartialLogMetaData around to re-use... or usage a sync/pool?
I think just keeping a single one should work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since the copy is sequential, I'm now simply using one allocated object over all msgs. Would that work for you?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As discussed, let's just keep this as is for now since some log drivers handle messages asynchronously.
Thanks!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done!

Docker daemon has a 16K buffer for log messages. If a message length
exceeds 16K, it should be split by the logger and merged at the
endpoint.

This change adds `PartialLogMetaData` struct for enhanced partial support
- LastPartial (bool) : indicates if this is the last of all partials.
- ID (string)        : unique 32 bit ID. ID is same across all partials.
- Ordinal (int starts at 1) : indicates the position of msg in the series of partials.
Also, the timestamps across partials in the same.

Signed-off-by: Anusha Ragunathan <anusha.ragunathan@docker.com>

@cpuguy83 cpuguy83 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@thaJeztah

Copy link
Copy Markdown
Member

These are known flaky's, tracked through #36501

21:45:58 ----------------------------------------------------------------------
21:45:58 FAIL: docker_api_swarm_service_test.go:33: DockerSwarmSuite.TestAPIServiceUpdatePort
21:45:58 
21:45:58 [ddf763c4c66ae] waiting for daemon to start
21:45:58 [ddf763c4c66ae] daemon started
21:45:58 
21:45:58 docker_api_swarm_service_test.go:39:
21:45:58     waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
21:45:58 docker_utils_test.go:452:
21:45:58     c.Assert(v, checker, args...)
21:45:58 ... obtained int = 0
21:45:58 ... expected int = 1
21:45:58 
21:45:58 [ddf763c4c66ae] exiting daemon
21:46:10 

22:10:50 ----------------------------------------------------------------------
22:10:50 FAIL: docker_cli_swarm_test.go:1605: DockerSwarmSuite.TestSwarmPublishDuplicatePorts
22:10:50 
22:10:50 [de0f01c91cd86] waiting for daemon to start
22:10:50 [de0f01c91cd86] daemon started
22:10:50 
22:10:50 docker_cli_swarm_test.go:1613:
22:10:50     // make sure task has been deployed.
22:10:50     waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
22:10:50 docker_utils_test.go:452:
22:10:50     c.Assert(v, checker, args...)
22:10:50 ... obtained int = 0
22:10:50 ... expected int = 1
22:10:50 
22:10:50 [de0f01c91cd86] exiting daemon
22:10:53 

This one looks to have become flaky again (tracking issue: #32673). I attached the daemon logs for that test
docker.log.txt

21:48:21 ----------------------------------------------------------------------
21:48:21 FAIL: docker_api_swarm_test.go:297: DockerSwarmSuite.TestAPISwarmLeaderElection
21:48:21 
21:48:21 [db7b38f7b479e] waiting for daemon to start
21:48:21 [db7b38f7b479e] daemon started
21:48:21 
21:48:21 [d0ba13e9ba563] waiting for daemon to start
21:48:21 [d0ba13e9ba563] daemon started
21:48:21 
21:48:21 [df5215dd8a143] waiting for daemon to start
21:48:21 [df5215dd8a143] daemon started
21:48:21 
21:48:21 [db7b38f7b479e] exiting daemon
21:48:21 assertion failed: error is not nil: Error response from daemon: rpc error: code = DeadlineExceeded desc = context deadline exceeded
21:48:21 [d0ba13e9ba563] exiting daemon
21:48:21 [df5215dd8a143] exiting daemon

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks!

@sharonx

sharonx commented Apr 13, 2018

Copy link
Copy Markdown

splunk-logging-plugin is already using the Partial flag now to reassemble messages. This change is a breaking change for our plugins. I assume this change would go in a major release?

@cpuguy83

Copy link
Copy Markdown
Member

@sharonx this is an internal only change and opens up built-in drivers to support the additional parameters.

Plugins will require some extra work to expose this data to the plugin, but there should be no change to the data currently being sent to the plugin. When the work is done to bring plugins up to speed with thos change it will be purely additive.

@kyaparla

Copy link
Copy Markdown

Hi All,

I am using splunk logging driver to send logs to splunk, and noticed that, when splunk-format is inline, we are able to send messages >10K in size, but when sending them in raw format, message gets truncated at 4K, is that expected? Can someone provide any pointers on this issue, if this is not the right place?

@anusha-ragunathan

Copy link
Copy Markdown
Contributor Author

@kyaparla : Messages get split at 16K. So what you are observing is not expected.
Also, the issue you describe is not related to this PR. Please open a new issue and cc @sharonx and @chenziliang from Splunk.

@kyaparla

Copy link
Copy Markdown

Thanks @anusha-ragunathan, opened this issue Splunk logging driver truncates messages at 4K size when splunk-format is set to raw #37096

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.