{"action":"created","comment":{"url":"https://api.github.com/repos/RisingStack/trace-go/pulls/comments/45263076","id":45263076,"diff_hunk":"@@ -0,0 +1,142 @@\n+package trace\n+\n+import (\n+\t\"crypto/aes\"\n+\t\"crypto/cipher\"\n+\t\"crypto/rand\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"log\"\n+\t\"net/http\"\n+\t\"strconv\"\n+\t\"sync\"\n+\t\"unsafe\"\n+)\n+\n+type ID uint64\n+\n+// appdash String()\n+func (id *ID) String() string {\n+\treturn fmt.Sprintf(\"%016x\", uint64(*id))\n+}\n+\n+// appdash ParseID\n+func ParseID(s string) (ID, error) {\n+\ti, err := strconv.ParseUint(s, 16, 64)\n+\tif err != nil {\n+\t\treturn 0, err\n+\t}\n+\treturn ID(i), nil\n+}\n+\n+const (\n+\tidSize  = aes.BlockSize / 2 // 64 bits\n+\tkeySize = aes.BlockSize     // 128 bits\n+)\n+\n+var (\n+\tctr []byte\n+\tn   int\n+\tb   []byte\n+\tc   cipher.Block\n+\tm   sync.Mutex\n+)\n+\n+func init() {\n+\tbuf := make([]byte, keySize+aes.BlockSize)\n+\t_, err := io.ReadFull(rand.Reader, buf)\n+\tif err != nil {\n+\t\tpanic(err) // /dev/urandom had better work\n+\t}\n+\tc, err = aes.NewCipher(buf[:keySize])\n+\tif err != nil {\n+\t\tpanic(err) // AES had better work\n+\t}\n+\tn = aes.BlockSize\n+\tctr = buf[keySize:]\n+\tb = make([]byte, aes.BlockSize)\n+}\n+\n+// appdash generateID\n+func NewID() ID {\n+\tm.Lock()\n+\tif n == aes.BlockSize {\n+\t\tc.Encrypt(b, ctr)\n+\t\tfor i := aes.BlockSize - 1; i >= 0; i-- { // increment ctr\n+\t\t\tctr[i]++\n+\t\t\tif ctr[i] != 0 {\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t}\n+\t\tn = 0\n+\t}\n+\tid := *(*ID)(unsafe.Pointer(&b[n])) // zero-copy b/c we're arch-neutral\n+\tn += idSize\n+\tm.Unlock()\n+\treturn id\n+}\n+\n+type SpanID struct {\n+\tTrace  ID\n+\tSpan   ID\n+\tParent ID\n+}\n+\n+func (s *SpanID) IsRoot() bool {\n+\treturn s.Trace == 0\n+}\n+\n+func (s *SpanID) String() string {\n+\treturn fmt.Sprintf(\"<T:%s,S:%s,P:%s>\", s.Trace.String(), s.Span.String(), s.Parent.String())\n+}\n+\n+func NewRootSpanID() SpanID {\n+\treturn SpanID{\n+\t\tTrace: NewID(),\n+\t\tSpan:  NewID(),\n+\t}\n+}\n+\n+func NewSpanID(parent SpanID) SpanID {\n+\treturn SpanID{\n+\t\tTrace:  parent.Trace,\n+\t\tSpan:   NewID(),\n+\t\tParent: parent.Span,\n+\t}\n+}\n+\n+func NewSpanIDFromRequest(req *http.Request) SpanID {\n+\tparentSpanID := ParseSpanID(req)\n+\tif parentSpanID.IsRoot() {\n+\t\treturn NewRootSpanID()\n+\t}\n+\treturn NewSpanID(parentSpanID)\n+}\n+\n+func ParseSpanID(req *http.Request) SpanID {\n+\tspanIDStr := req.Header.Get(HeaderSpanID)\n+\ttraceIDStr := req.Header.Get(HeaderTraceID)\n+\tspanID, err := ParseID(spanIDStr)\n+\tif err != nil {\n+\t\tlog.Println(\"Failed to parse spanID string value, using 0.\")\n+\t}\n+\ttraceID, err := ParseID(traceIDStr)\n+\tif err != nil {\n+\t\tlog.Println(\"Failed to parse traceID string value, using 0.\")\n+\t}\n+\treturn SpanID{\n+\t\tTrace: traceID,\n+\t\tSpan:  spanID,\n+\t}\n+}\n+\n+func (i *ID) MarshalJSON() ([]byte, error) {\n+\treturn []byte(\"\\\"\" + i.String() + \"\\\"\"), nil","path":"trace/id.go","position":null,"original_position":134,"commit_id":"fb3a013e1de3496fbdab4538cc1e4727a398eb17","original_commit_id":"7c0732d1c4405aaad81fcba87c7a28c3d89acc38","user":{"login":"gulyasm","id":2179258,"avatar_url":"https://avatars.githubusercontent.com/u/2179258?v=3","gravatar_id":"","url":"https://api.github.com/users/gulyasm","html_url":"https://github.com/gulyasm","followers_url":"https://api.github.com/users/gulyasm/followers","following_url":"https://api.github.com/users/gulyasm/following{/other_user}","gists_url":"https://api.github.com/users/gulyasm/gists{/gist_id}","starred_url":"https://api.github.com/users/gulyasm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gulyasm/subscriptions","organizations_url":"https://api.github.com/users/gulyasm/orgs","repos_url":"https://api.github.com/users/gulyasm/repos","events_url":"https://api.github.com/users/gulyasm/events{/privacy}","received_events_url":"https://api.github.com/users/gulyasm/received_events","type":"User","site_admin":false},"body":":+1: ","created_at":"2015-11-18T21:29:26Z","updated_at":"2015-11-18T21:29:26Z","html_url":"https://github.com/RisingStack/trace-go/pull/1#discussion_r45263076","pull_request_url":"https://api.github.com/repos/RisingStack/trace-go/pulls/1","_links":{"self":{"href":"https://api.github.com/repos/RisingStack/trace-go/pulls/comments/45263076"},"html":{"href":"https://github.com/RisingStack/trace-go/pull/1#discussion_r45263076"},"pull_request":{"href":"https://api.github.com/repos/RisingStack/trace-go/pulls/1"}}},"pull_request":{"url":"https://api.github.com/repos/RisingStack/trace-go/pulls/1","id":47455989,"html_url":"https://github.com/RisingStack/trace-go/pull/1","diff_url":"https://github.com/RisingStack/trace-go/pull/1.diff","patch_url":"https://github.com/RisingStack/trace-go/pull/1.patch","issue_url":"https://api.github.com/repos/RisingStack/trace-go/issues/1","number":1,"state":"open","locked":false,"title":"First implementation","user":{"login":"gulyasm","id":2179258,"avatar_url":"https://avatars.githubusercontent.com/u/2179258?v=3","gravatar_id":"","url":"https://api.github.com/users/gulyasm","html_url":"https://github.com/gulyasm","followers_url":"https://api.github.com/users/gulyasm/followers","following_url":"https://api.github.com/users/gulyasm/following{/other_user}","gists_url":"https://api.github.com/users/gulyasm/gists{/gist_id}","starred_url":"https://api.github.com/users/gulyasm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gulyasm/subscriptions","organizations_url":"https://api.github.com/users/gulyasm/orgs","repos_url":"https://api.github.com/users/gulyasm/repos","events_url":"https://api.github.com/users/gulyasm/events{/privacy}","received_events_url":"https://api.github.com/users/gulyasm/received_events","type":"User","site_admin":false},"body":" _**Note:** This PR is not complete, I submitted it for early code review._\r\n## What is in this PR?\r\n- ID type with JSON serialization, deserialization, String method for human readable format. ID generation is statistically unique. The implementation comes from the appdash trace.\r\n- SpanID for easy handling\r\n- Event type\r\n- Memory collector for testing purposes\r\n- Trace RoundTripper implementation, that sets the ID for outgoing requests, reports the events.\r\n- Trace method for instrumenting handlers. It sets the headers and record the events.\r\n- Example changed to represent the new approach.\r\n\r\n## What left to complete this PR?\r\n- [x] Restructure code with reasonable structure. (header handling should go to `header.go`)\r\n- [ ] Unit tests\r\n- [ ] Check naming. Some function names and the header names might be changed with better candidates.\r\n- [ ] Middleware for popular middleware systems.\r\n- [ ] Example on how to use it with middlewares (Negorni, Gorilla)\r\n- [ ] Better documentation\r\n\r\n## Other notes\r\n- Part of the codebase (ID, SpanID) comes from the appdash trace library. (https://github.com/sourcegraph/appdash)\r\n","created_at":"2015-10-12T19:33:10Z","updated_at":"2015-11-18T21:29:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b76b81442fb0e0702c1addd19cf6f1ddc3f7f3c8","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/RisingStack/trace-go/pulls/1/commits","review_comments_url":"https://api.github.com/repos/RisingStack/trace-go/pulls/1/comments","review_comment_url":"https://api.github.com/repos/RisingStack/trace-go/pulls/comments{/number}","comments_url":"https://api.github.com/repos/RisingStack/trace-go/issues/1/comments","statuses_url":"https://api.github.com/repos/RisingStack/trace-go/statuses/fb3a013e1de3496fbdab4538cc1e4727a398eb17","head":{"label":"RisingStack:draft-1.0","ref":"draft-1.0","sha":"fb3a013e1de3496fbdab4538cc1e4727a398eb17","user":{"login":"RisingStack","id":6916052,"avatar_url":"https://avatars.githubusercontent.com/u/6916052?v=3","gravatar_id":"","url":"https://api.github.com/users/RisingStack","html_url":"https://github.com/RisingStack","followers_url":"https://api.github.com/users/RisingStack/followers","following_url":"https://api.github.com/users/RisingStack/following{/other_user}","gists_url":"https://api.github.com/users/RisingStack/gists{/gist_id}","starred_url":"https://api.github.com/users/RisingStack/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RisingStack/subscriptions","organizations_url":"https://api.github.com/users/RisingStack/orgs","repos_url":"https://api.github.com/users/RisingStack/repos","events_url":"https://api.github.com/users/RisingStack/events{/privacy}","received_events_url":"https://api.github.com/users/RisingStack/received_events","type":"Organization","site_admin":false},"repo":{"id":42303848,"name":"trace-go","full_name":"RisingStack/trace-go","owner":{"login":"RisingStack","id":6916052,"avatar_url":"https://avatars.githubusercontent.com/u/6916052?v=3","gravatar_id":"","url":"https://api.github.com/users/RisingStack","html_url":"https://github.com/RisingStack","followers_url":"https://api.github.com/users/RisingStack/followers","following_url":"https://api.github.com/users/RisingStack/following{/other_user}","gists_url":"https://api.github.com/users/RisingStack/gists{/gist_id}","starred_url":"https://api.github.com/users/RisingStack/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RisingStack/subscriptions","organizations_url":"https://api.github.com/users/RisingStack/orgs","repos_url":"https://api.github.com/users/RisingStack/repos","events_url":"https://api.github.com/users/RisingStack/events{/privacy}","received_events_url":"https://api.github.com/users/RisingStack/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/RisingStack/trace-go","description":"Trace is a visualised stack trace platform designed for microservices.","fork":false,"url":"https://api.github.com/repos/RisingStack/trace-go","forks_url":"https://api.github.com/repos/RisingStack/trace-go/forks","keys_url":"https://api.github.com/repos/RisingStack/trace-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/RisingStack/trace-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/RisingStack/trace-go/teams","hooks_url":"https://api.github.com/repos/RisingStack/trace-go/hooks","issue_events_url":"https://api.github.com/repos/RisingStack/trace-go/issues/events{/number}","events_url":"https://api.github.com/repos/RisingStack/trace-go/events","assignees_url":"https://api.github.com/repos/RisingStack/trace-go/assignees{/user}","branches_url":"https://api.github.com/repos/RisingStack/trace-go/branches{/branch}","tags_url":"https://api.github.com/repos/RisingStack/trace-go/tags","blobs_url":"https://api.github.com/repos/RisingStack/trace-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/RisingStack/trace-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/RisingStack/trace-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/RisingStack/trace-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/RisingStack/trace-go/statuses/{sha}","languages_url":"https://api.github.com/repos/RisingStack/trace-go/languages","stargazers_url":"https://api.github.com/repos/RisingStack/trace-go/stargazers","contributors_url":"https://api.github.com/repos/RisingStack/trace-go/contributors","subscribers_url":"https://api.github.com/repos/RisingStack/trace-go/subscribers","subscription_url":"https://api.github.com/repos/RisingStack/trace-go/subscription","commits_url":"https://api.github.com/repos/RisingStack/trace-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/RisingStack/trace-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/RisingStack/trace-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/RisingStack/trace-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/RisingStack/trace-go/contents/{+path}","compare_url":"https://api.github.com/repos/RisingStack/trace-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/RisingStack/trace-go/merges","archive_url":"https://api.github.com/repos/RisingStack/trace-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/RisingStack/trace-go/downloads","issues_url":"https://api.github.com/repos/RisingStack/trace-go/issues{/number}","pulls_url":"https://api.github.com/repos/RisingStack/trace-go/pulls{/number}","milestones_url":"https://api.github.com/repos/RisingStack/trace-go/milestones{/number}","notifications_url":"https://api.github.com/repos/RisingStack/trace-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/RisingStack/trace-go/labels{/name}","releases_url":"https://api.github.com/repos/RisingStack/trace-go/releases{/id}","created_at":"2015-09-11T11:05:33Z","updated_at":"2015-10-18T07:52:21Z","pushed_at":"2015-11-18T21:21:44Z","git_url":"git://github.com/RisingStack/trace-go.git","ssh_url":"git@github.com:RisingStack/trace-go.git","clone_url":"https://github.com/RisingStack/trace-go.git","svn_url":"https://github.com/RisingStack/trace-go","homepage":"http://trace.risingstack.com","size":21,"stargazers_count":5,"watchers_count":5,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":5,"default_branch":"master"}},"base":{"label":"RisingStack:master","ref":"master","sha":"089ef556d6169a419f44d9c97fbac0390c42243b","user":{"login":"RisingStack","id":6916052,"avatar_url":"https://avatars.githubusercontent.com/u/6916052?v=3","gravatar_id":"","url":"https://api.github.com/users/RisingStack","html_url":"https://github.com/RisingStack","followers_url":"https://api.github.com/users/RisingStack/followers","following_url":"https://api.github.com/users/RisingStack/following{/other_user}","gists_url":"https://api.github.com/users/RisingStack/gists{/gist_id}","starred_url":"https://api.github.com/users/RisingStack/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RisingStack/subscriptions","organizations_url":"https://api.github.com/users/RisingStack/orgs","repos_url":"https://api.github.com/users/RisingStack/repos","events_url":"https://api.github.com/users/RisingStack/events{/privacy}","received_events_url":"https://api.github.com/users/RisingStack/received_events","type":"Organization","site_admin":false},"repo":{"id":42303848,"name":"trace-go","full_name":"RisingStack/trace-go","owner":{"login":"RisingStack","id":6916052,"avatar_url":"https://avatars.githubusercontent.com/u/6916052?v=3","gravatar_id":"","url":"https://api.github.com/users/RisingStack","html_url":"https://github.com/RisingStack","followers_url":"https://api.github.com/users/RisingStack/followers","following_url":"https://api.github.com/users/RisingStack/following{/other_user}","gists_url":"https://api.github.com/users/RisingStack/gists{/gist_id}","starred_url":"https://api.github.com/users/RisingStack/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RisingStack/subscriptions","organizations_url":"https://api.github.com/users/RisingStack/orgs","repos_url":"https://api.github.com/users/RisingStack/repos","events_url":"https://api.github.com/users/RisingStack/events{/privacy}","received_events_url":"https://api.github.com/users/RisingStack/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/RisingStack/trace-go","description":"Trace is a visualised stack trace platform designed for microservices.","fork":false,"url":"https://api.github.com/repos/RisingStack/trace-go","forks_url":"https://api.github.com/repos/RisingStack/trace-go/forks","keys_url":"https://api.github.com/repos/RisingStack/trace-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/RisingStack/trace-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/RisingStack/trace-go/teams","hooks_url":"https://api.github.com/repos/RisingStack/trace-go/hooks","issue_events_url":"https://api.github.com/repos/RisingStack/trace-go/issues/events{/number}","events_url":"https://api.github.com/repos/RisingStack/trace-go/events","assignees_url":"https://api.github.com/repos/RisingStack/trace-go/assignees{/user}","branches_url":"https://api.github.com/repos/RisingStack/trace-go/branches{/branch}","tags_url":"https://api.github.com/repos/RisingStack/trace-go/tags","blobs_url":"https://api.github.com/repos/RisingStack/trace-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/RisingStack/trace-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/RisingStack/trace-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/RisingStack/trace-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/RisingStack/trace-go/statuses/{sha}","languages_url":"https://api.github.com/repos/RisingStack/trace-go/languages","stargazers_url":"https://api.github.com/repos/RisingStack/trace-go/stargazers","contributors_url":"https://api.github.com/repos/RisingStack/trace-go/contributors","subscribers_url":"https://api.github.com/repos/RisingStack/trace-go/subscribers","subscription_url":"https://api.github.com/repos/RisingStack/trace-go/subscription","commits_url":"https://api.github.com/repos/RisingStack/trace-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/RisingStack/trace-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/RisingStack/trace-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/RisingStack/trace-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/RisingStack/trace-go/contents/{+path}","compare_url":"https://api.github.com/repos/RisingStack/trace-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/RisingStack/trace-go/merges","archive_url":"https://api.github.com/repos/RisingStack/trace-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/RisingStack/trace-go/downloads","issues_url":"https://api.github.com/repos/RisingStack/trace-go/issues{/number}","pulls_url":"https://api.github.com/repos/RisingStack/trace-go/pulls{/number}","milestones_url":"https://api.github.com/repos/RisingStack/trace-go/milestones{/number}","notifications_url":"https://api.github.com/repos/RisingStack/trace-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/RisingStack/trace-go/labels{/name}","releases_url":"https://api.github.com/repos/RisingStack/trace-go/releases{/id}","created_at":"2015-09-11T11:05:33Z","updated_at":"2015-10-18T07:52:21Z","pushed_at":"2015-11-18T21:21:44Z","git_url":"git://github.com/RisingStack/trace-go.git","ssh_url":"git@github.com:RisingStack/trace-go.git","clone_url":"https://github.com/RisingStack/trace-go.git","svn_url":"https://github.com/RisingStack/trace-go","homepage":"http://trace.risingstack.com","size":21,"stargazers_count":5,"watchers_count":5,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/RisingStack/trace-go/pulls/1"},"html":{"href":"https://github.com/RisingStack/trace-go/pull/1"},"issue":{"href":"https://api.github.com/repos/RisingStack/trace-go/issues/1"},"comments":{"href":"https://api.github.com/repos/RisingStack/trace-go/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/RisingStack/trace-go/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/RisingStack/trace-go/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/RisingStack/trace-go/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/RisingStack/trace-go/statuses/fb3a013e1de3496fbdab4538cc1e4727a398eb17"}}}}