{"action":"created","comment":{"url":"https://api.github.com/repos/docker/swarmkit/pulls/comments/85228089","pull_request_review_id":5955850,"id":85228089,"diff_hunk":"@@ -0,0 +1,174 @@\n+syntax = \"proto3\";\n+\n+package docker.swarmkit.v1;\n+\n+import \"gogoproto/gogo.proto\";\n+import \"timestamp/timestamp.proto\"; // TODO(stevvooe): use our own until we fix gogoproto/deepcopy\n+import \"plugin/plugin.proto\";\n+\n+// LogStream defines the stream from which the log message came.\n+enum LogStream {\n+\toption (gogoproto.goproto_enum_prefix) = false;\n+\toption (gogoproto.enum_customname) = \"LogStream\";\n+\n+\tLOG_STREAM_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = \"LogStreamUnknown\"];\n+\tLOG_STREAM_STDOUT = 1 [(gogoproto.enumvalue_customname) = \"LogStreamStdout\"];\n+\tLOG_STREAM_STDERR = 2 [(gogoproto.enumvalue_customname) = \"LogStreamStderr\"];\n+}\n+\n+message LogSubscriptionOptions {\n+\t// Streams defines which log streams should be sent from the task source.\n+\t// Empty means send all the messages.\n+\trepeated LogStream streams = 1;\n+\n+\t// Follow instructs the publisher to continue sending log messages as they\n+\t// are produced, after satisfying the initial query.\n+\tbool follow = 2;\n+\n+\t// Tail defines how many messages relative to the log stream to send when\n+\t// starting the stream.\n+\t//\n+\t// Positive values will skip that number of messages from the start of the\n+\t// stream before publishing.\n+\t//\n+\t// Negative values will specify messages relative to the end of the stream,\n+\t// offset by one. We can say that the last (-n-1) lines are returned when n\n+\t// < 0. As reference, -1 would mean send no log lines (typically used with\n+\t// follow), -2 would return the last log line, -11 would return the last 10\n+\t// and so on.\n+\t//\n+\t// The default value of zero will return all logs.\n+\t//\n+\t// Note that this is very different from the Docker API.\n+\tint64 tail = 3;\n+\n+\t// Since indicates that only log messages produced after this timestamp\n+\t// should be sent.\n+\tTimestamp since = 4;\n+}\n+\n+// LogSelector will match logs from ANY of the defined parameters.\n+//\n+// For the best effect, the client should use the least specific parameter\n+// possible. For example, if they want to listen to all the tasks of a service,\n+// they should use the service id, rather than specifying the individual tasks.\n+message LogSelector {\n+\trepeated string service_ids = 1 [(gogoproto.customname) = \"ServiceIDs\"];\n+\trepeated string node_ids = 2 [(gogoproto.customname) = \"NodeIDs\"];\n+\trepeated string task_ids = 3 [(gogoproto.customname) = \"TaskIDs\"];\n+}\n+\n+// LogContext marks the context from which a log message was generated.\n+message LogContext {\n+\tstring service_id = 1 [(gogoproto.customname) = \"ServiceID\"];\n+\tstring node_id = 2 [(gogoproto.customname) = \"NodeID\"];\n+\tstring task_id = 3 [(gogoproto.customname) = \"TaskID\"];\n+}\n+\n+// LogMessage \n+message LogMessage {\n+\t// Context identifies the source of the log message.\n+\tLogContext context = 1 [(gogoproto.nullable) = false];\n+\n+\t// Timestamp is the time at which the message was generated.\n+\tTimestamp timestamp = 2;\n+\n+\t// Stream identifies the stream of the log message, stdout or stderr.\n+\tLogStream stream = 3;\n+\n+\t// Data is the raw log message, as generated by the application.\n+\tbytes data = 4;\n+}\n+\n+// Logs defines the methods for retrieving task logs messages from a cluster.\n+service Logs {\n+\t// SubscribeLogs starts a subscription with the specified selector and options.\n+\t//\n+\t// The subscription will be distributed to relevant nodes and messages will\n+\t// be collected and sent via the returned stream.\n+\t//\n+\t// The subscription will end with an EOF.\n+\trpc SubscribeLogs(SubscribeLogsRequest) returns (stream SubscribeLogsMessage) {\n+\t\toption (docker.protobuf.plugin.tls_authorization) = { roles: \"swarm-manager\" };\n+\t}\n+}\n+\n+message SubscribeLogsRequest {\n+\t// LogSelector describes the logs to which the subscriber is \n+\tLogSelector selector = 1;\n+\n+\tLogSubscriptionOptions options = 2;\n+}\n+\n+message SubscribeLogsMessage {\n+\trepeated LogMessage messages = 1 [(gogoproto.nullable) = false];\n+}\n+\n+// LogBroker defines the API used by the worker to send task logs back to a\n+// manager. A client listens for subscriptions then optimistically retrieves\n+// logs satisfying said subscriptions, calling PublishLogs for results that are\n+// relevant.\n+//\n+// The structure of ListenSubscriptions is similar to the Dispatcher API but\n+// decoupled to allow log distribution to work outside of the regular task\n+// flow.\n+service LogBroker {\n+\t// ListenSubscriptions starts a subscription stream for the node. For each\n+\t// message received, the node should attempt to satisfy the subscription.\n+\t//\n+\t// Log messages that match the provided subscription should be sent via\n+\t// PublishLogs.\n+\trpc ListenSubscriptions(ListenSubscriptionsRequest) returns (stream SubscriptionMessage) {\n+\t\toption (docker.protobuf.plugin.tls_authorization) = {\n+\t\t\troles: \"swarm-worker\"\n+\t\t\troles: \"swarm-manager\"\n+\t\t};\n+\t}\n+\n+\t// PublishLogs receives sets of log messages destined for a single\n+\t// subscription identifier.\n+\trpc PublishLogs(PublishLogsRequest) returns (PublishLogsResponse) {","path":"api/logbroker.proto","position":130,"original_position":130,"commit_id":"36c3408778090c4c5ed1a69c11dc03f3f30852f4","original_commit_id":"a6972884d5829ab3c185c27e2f4fc332ed35a7d1","user":{"login":"aaronlehmann","id":10601430,"avatar_url":"https://avatars.githubusercontent.com/u/10601430?v=3","gravatar_id":"","url":"https://api.github.com/users/aaronlehmann","html_url":"https://github.com/aaronlehmann","followers_url":"https://api.github.com/users/aaronlehmann/followers","following_url":"https://api.github.com/users/aaronlehmann/following{/other_user}","gists_url":"https://api.github.com/users/aaronlehmann/gists{/gist_id}","starred_url":"https://api.github.com/users/aaronlehmann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaronlehmann/subscriptions","organizations_url":"https://api.github.com/users/aaronlehmann/orgs","repos_url":"https://api.github.com/users/aaronlehmann/repos","events_url":"https://api.github.com/users/aaronlehmann/events{/privacy}","received_events_url":"https://api.github.com/users/aaronlehmann/received_events","type":"User","site_admin":false},"body":"Any thoughts about making this a client streaming RPC instead of a one-off RPC? I don't have a good sense of the overhead that each kind of RPC has, but I'd imagine a node will typically publish many messages as part of a log subscription, and by using a stream instead of many RPC invocations, we'd lower the cost of the things like the TLS authorization checks that have to run every time the RPC is invoked.","created_at":"2016-10-26T21:49:19Z","updated_at":"2016-10-26T21:49:19Z","html_url":"https://github.com/docker/swarmkit/pull/1679#discussion_r85228089","pull_request_url":"https://api.github.com/repos/docker/swarmkit/pulls/1679","_links":{"self":{"href":"https://api.github.com/repos/docker/swarmkit/pulls/comments/85228089"},"html":{"href":"https://github.com/docker/swarmkit/pull/1679#discussion_r85228089"},"pull_request":{"href":"https://api.github.com/repos/docker/swarmkit/pulls/1679"}}},"pull_request":{"url":"https://api.github.com/repos/docker/swarmkit/pulls/1679","id":90464621,"html_url":"https://github.com/docker/swarmkit/pull/1679","diff_url":"https://github.com/docker/swarmkit/pull/1679.diff","patch_url":"https://github.com/docker/swarmkit/pull/1679.patch","issue_url":"https://api.github.com/repos/docker/swarmkit/issues/1679","number":1679,"state":"open","locked":false,"title":"Log Management","user":{"login":"aluzzardi","id":179503,"avatar_url":"https://avatars.githubusercontent.com/u/179503?v=3","gravatar_id":"","url":"https://api.github.com/users/aluzzardi","html_url":"https://github.com/aluzzardi","followers_url":"https://api.github.com/users/aluzzardi/followers","following_url":"https://api.github.com/users/aluzzardi/following{/other_user}","gists_url":"https://api.github.com/users/aluzzardi/gists{/gist_id}","starred_url":"https://api.github.com/users/aluzzardi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aluzzardi/subscriptions","organizations_url":"https://api.github.com/users/aluzzardi/orgs","repos_url":"https://api.github.com/users/aluzzardi/repos","events_url":"https://api.github.com/users/aluzzardi/events{/privacy}","received_events_url":"https://api.github.com/users/aluzzardi/received_events","type":"User","site_admin":false},"body":"This change adds support for log management in the manager, agent and\r\nCLI.\r\n\r\nThe log broker is currently naive and broadcasts subscriptions to all\r\nagents, which in turn need to perform filtering to figure out if the\r\nsubscription is relevant to them.\r\n\r\nIn the future, the broker should be smarter and dispatch subscriptions\r\nonly to concerned agents.\r\n\r\nThe basic logging functionality works.\r\n\r\nFixes #1332\r\n\r\n/cc @stevvooe @aaronlehmann @diogomonica ","created_at":"2016-10-22T01:06:04Z","updated_at":"2016-10-26T21:49:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8b7f6dd1eb7bbeb386e898b12d1aeca933c89ff5","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/docker/swarmkit/pulls/1679/commits","review_comments_url":"https://api.github.com/repos/docker/swarmkit/pulls/1679/comments","review_comment_url":"https://api.github.com/repos/docker/swarmkit/pulls/comments{/number}","comments_url":"https://api.github.com/repos/docker/swarmkit/issues/1679/comments","statuses_url":"https://api.github.com/repos/docker/swarmkit/statuses/36c3408778090c4c5ed1a69c11dc03f3f30852f4","head":{"label":"aluzzardi:logbroker","ref":"logbroker","sha":"36c3408778090c4c5ed1a69c11dc03f3f30852f4","user":{"login":"aluzzardi","id":179503,"avatar_url":"https://avatars.githubusercontent.com/u/179503?v=3","gravatar_id":"","url":"https://api.github.com/users/aluzzardi","html_url":"https://github.com/aluzzardi","followers_url":"https://api.github.com/users/aluzzardi/followers","following_url":"https://api.github.com/users/aluzzardi/following{/other_user}","gists_url":"https://api.github.com/users/aluzzardi/gists{/gist_id}","starred_url":"https://api.github.com/users/aluzzardi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aluzzardi/subscriptions","organizations_url":"https://api.github.com/users/aluzzardi/orgs","repos_url":"https://api.github.com/users/aluzzardi/repos","events_url":"https://api.github.com/users/aluzzardi/events{/privacy}","received_events_url":"https://api.github.com/users/aluzzardi/received_events","type":"User","site_admin":false},"repo":{"id":60661626,"name":"swarmkit","full_name":"aluzzardi/swarmkit","owner":{"login":"aluzzardi","id":179503,"avatar_url":"https://avatars.githubusercontent.com/u/179503?v=3","gravatar_id":"","url":"https://api.github.com/users/aluzzardi","html_url":"https://github.com/aluzzardi","followers_url":"https://api.github.com/users/aluzzardi/followers","following_url":"https://api.github.com/users/aluzzardi/following{/other_user}","gists_url":"https://api.github.com/users/aluzzardi/gists{/gist_id}","starred_url":"https://api.github.com/users/aluzzardi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aluzzardi/subscriptions","organizations_url":"https://api.github.com/users/aluzzardi/orgs","repos_url":"https://api.github.com/users/aluzzardi/repos","events_url":"https://api.github.com/users/aluzzardi/events{/privacy}","received_events_url":"https://api.github.com/users/aluzzardi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/aluzzardi/swarmkit","description":"A toolkit for embedding orchestration and cluster management capabilities in your application","fork":true,"url":"https://api.github.com/repos/aluzzardi/swarmkit","forks_url":"https://api.github.com/repos/aluzzardi/swarmkit/forks","keys_url":"https://api.github.com/repos/aluzzardi/swarmkit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aluzzardi/swarmkit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aluzzardi/swarmkit/teams","hooks_url":"https://api.github.com/repos/aluzzardi/swarmkit/hooks","issue_events_url":"https://api.github.com/repos/aluzzardi/swarmkit/issues/events{/number}","events_url":"https://api.github.com/repos/aluzzardi/swarmkit/events","assignees_url":"https://api.github.com/repos/aluzzardi/swarmkit/assignees{/user}","branches_url":"https://api.github.com/repos/aluzzardi/swarmkit/branches{/branch}","tags_url":"https://api.github.com/repos/aluzzardi/swarmkit/tags","blobs_url":"https://api.github.com/repos/aluzzardi/swarmkit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aluzzardi/swarmkit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aluzzardi/swarmkit/git/refs{/sha}","trees_url":"https://api.github.com/repos/aluzzardi/swarmkit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aluzzardi/swarmkit/statuses/{sha}","languages_url":"https://api.github.com/repos/aluzzardi/swarmkit/languages","stargazers_url":"https://api.github.com/repos/aluzzardi/swarmkit/stargazers","contributors_url":"https://api.github.com/repos/aluzzardi/swarmkit/contributors","subscribers_url":"https://api.github.com/repos/aluzzardi/swarmkit/subscribers","subscription_url":"https://api.github.com/repos/aluzzardi/swarmkit/subscription","commits_url":"https://api.github.com/repos/aluzzardi/swarmkit/commits{/sha}","git_commits_url":"https://api.github.com/repos/aluzzardi/swarmkit/git/commits{/sha}","comments_url":"https://api.github.com/repos/aluzzardi/swarmkit/comments{/number}","issue_comment_url":"https://api.github.com/repos/aluzzardi/swarmkit/issues/comments{/number}","contents_url":"https://api.github.com/repos/aluzzardi/swarmkit/contents/{+path}","compare_url":"https://api.github.com/repos/aluzzardi/swarmkit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aluzzardi/swarmkit/merges","archive_url":"https://api.github.com/repos/aluzzardi/swarmkit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aluzzardi/swarmkit/downloads","issues_url":"https://api.github.com/repos/aluzzardi/swarmkit/issues{/number}","pulls_url":"https://api.github.com/repos/aluzzardi/swarmkit/pulls{/number}","milestones_url":"https://api.github.com/repos/aluzzardi/swarmkit/milestones{/number}","notifications_url":"https://api.github.com/repos/aluzzardi/swarmkit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aluzzardi/swarmkit/labels{/name}","releases_url":"https://api.github.com/repos/aluzzardi/swarmkit/releases{/id}","deployments_url":"https://api.github.com/repos/aluzzardi/swarmkit/deployments","created_at":"2016-06-08T02:19:36Z","updated_at":"2016-06-08T02:19:37Z","pushed_at":"2016-10-26T21:29:00Z","git_url":"git://github.com/aluzzardi/swarmkit.git","ssh_url":"git@github.com:aluzzardi/swarmkit.git","clone_url":"https://github.com/aluzzardi/swarmkit.git","svn_url":"https://github.com/aluzzardi/swarmkit","homepage":"","size":11164,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"docker:master","ref":"master","sha":"72981f443024da2c57d54b915eae0477be6dada5","user":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"repo":{"id":51556828,"name":"swarmkit","full_name":"docker/swarmkit","owner":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/docker/swarmkit","description":"A toolkit for orchestrating distributed systems at any scale. It includes primitives for node discovery, raft-based consensus, task scheduling and more.","fork":false,"url":"https://api.github.com/repos/docker/swarmkit","forks_url":"https://api.github.com/repos/docker/swarmkit/forks","keys_url":"https://api.github.com/repos/docker/swarmkit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/docker/swarmkit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/docker/swarmkit/teams","hooks_url":"https://api.github.com/repos/docker/swarmkit/hooks","issue_events_url":"https://api.github.com/repos/docker/swarmkit/issues/events{/number}","events_url":"https://api.github.com/repos/docker/swarmkit/events","assignees_url":"https://api.github.com/repos/docker/swarmkit/assignees{/user}","branches_url":"https://api.github.com/repos/docker/swarmkit/branches{/branch}","tags_url":"https://api.github.com/repos/docker/swarmkit/tags","blobs_url":"https://api.github.com/repos/docker/swarmkit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/docker/swarmkit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/docker/swarmkit/git/refs{/sha}","trees_url":"https://api.github.com/repos/docker/swarmkit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/docker/swarmkit/statuses/{sha}","languages_url":"https://api.github.com/repos/docker/swarmkit/languages","stargazers_url":"https://api.github.com/repos/docker/swarmkit/stargazers","contributors_url":"https://api.github.com/repos/docker/swarmkit/contributors","subscribers_url":"https://api.github.com/repos/docker/swarmkit/subscribers","subscription_url":"https://api.github.com/repos/docker/swarmkit/subscription","commits_url":"https://api.github.com/repos/docker/swarmkit/commits{/sha}","git_commits_url":"https://api.github.com/repos/docker/swarmkit/git/commits{/sha}","comments_url":"https://api.github.com/repos/docker/swarmkit/comments{/number}","issue_comment_url":"https://api.github.com/repos/docker/swarmkit/issues/comments{/number}","contents_url":"https://api.github.com/repos/docker/swarmkit/contents/{+path}","compare_url":"https://api.github.com/repos/docker/swarmkit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/docker/swarmkit/merges","archive_url":"https://api.github.com/repos/docker/swarmkit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/docker/swarmkit/downloads","issues_url":"https://api.github.com/repos/docker/swarmkit/issues{/number}","pulls_url":"https://api.github.com/repos/docker/swarmkit/pulls{/number}","milestones_url":"https://api.github.com/repos/docker/swarmkit/milestones{/number}","notifications_url":"https://api.github.com/repos/docker/swarmkit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/docker/swarmkit/labels{/name}","releases_url":"https://api.github.com/repos/docker/swarmkit/releases{/id}","deployments_url":"https://api.github.com/repos/docker/swarmkit/deployments","created_at":"2016-02-12T00:02:15Z","updated_at":"2016-10-26T12:27:40Z","pushed_at":"2016-10-26T21:44:38Z","git_url":"git://github.com/docker/swarmkit.git","ssh_url":"git@github.com:docker/swarmkit.git","clone_url":"https://github.com/docker/swarmkit.git","svn_url":"https://github.com/docker/swarmkit","homepage":"","size":22595,"stargazers_count":1006,"watchers_count":1006,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":199,"mirror_url":null,"open_issues_count":178,"forks":199,"open_issues":178,"watchers":1006,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/docker/swarmkit/pulls/1679"},"html":{"href":"https://github.com/docker/swarmkit/pull/1679"},"issue":{"href":"https://api.github.com/repos/docker/swarmkit/issues/1679"},"comments":{"href":"https://api.github.com/repos/docker/swarmkit/issues/1679/comments"},"review_comments":{"href":"https://api.github.com/repos/docker/swarmkit/pulls/1679/comments"},"review_comment":{"href":"https://api.github.com/repos/docker/swarmkit/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/docker/swarmkit/pulls/1679/commits"},"statuses":{"href":"https://api.github.com/repos/docker/swarmkit/statuses/36c3408778090c4c5ed1a69c11dc03f3f30852f4"}}}}
{"actor":{"display_login":"aaronlehmann"}}