)]}'
{
  "commit": "12971d6c8031d06f497c81ae1ed2a5bee488e7d2",
  "tree": "3332b72dda28e9c3d476aba0dd63d8465a3245f7",
  "parents": [
    "b0272187ee577a94edb803b81413165b7c1a89ba"
  ],
  "author": {
    "name": "Serge Bazanski",
    "email": "serge@nexantic.com",
    "time": "Tue Nov 17 12:12:58 2020 +0100"
  },
  "committer": {
    "name": "Serge Bazanski",
    "email": "serge@nexantic.com",
    "time": "Tue Nov 17 12:12:58 2020 +0100"
  },
  "message": "logtree: capture multiple lines in leveled log entries\n\nThis implements a solution to a disputed answer to the following\nquestion:\n\n    “What happens when someone calls Infof(\"foo\\nbar\")?”\n\nMultiple answers immediately present themselves:\n\n    a) Don\u0027t do anything, whatever consumers logs needs to expect that\n       they might contain newlines.\n    b) Yell/error/panic so that the programmer doesn\u0027t do this.\n    c) Split the one Info call into multiple Info calls, one per line,\n       somewhere in the logging path.\n\nFollowing the argumentation for these we establish the follwoing\nrequirments for any solution:\n\n    1) We want the programmer to be able to log multiple lines from a\n       single Info call and have that not fail. This is especially\n       important for reliability - we don\u0027t want an accidental codepath\n       that suddenly starts printing %s-formatted user-controlled\n       messages to start erroring out in production. This rules out b).\n    2) We want to allow emitting multiple lines that will not be\n       interleaved when viewing the log data. This rules out c).\n    3) We want to prohibit log injection by malicious \\n-containing\n       payloads (in case of %s-formatted user-controlled content). This\n       rules out a).\n    4) If multiple lines are allowed in a leveled payload, the type\n       system should support that, so that log consumers/tools will not\n       forget to account for the possible newlines. This too rules out\n       a).\n\nWith these in mind, we instead opt for a different solutions: changing\nthe API of logtree and logging protos to contain multiple possible lines\nper single log entry. This is a breaking change, but since all access to\nlogs is currently self-contained within the Monogon OS codebase, we can\nafford this.\n\nTo support this change, we change the access API (at LogEntry and\nLeveledPayload level) to contain two different methods for retrieving\nthe canonical representation of an entry:\n\n    fn String() string\n\nwhich returns a string with possible intra-string newlines (but no\ntrailing newlines), but with each newline-delimited chunk having the\ncanonical text representation prefix for this message. This prevents\nnewline injection into logs creating fake prefixes.\n\n    fn Strings() (prefix string, lines []string)\n\nwhich returns a common prefix for this entry (in its text\nrepresentation) and a set of lines that were contained in the original\nlog entry. This allows slightly smarter consuming code to make more\nactive decisions regarding the rendering of a multi-line entry, while\nstill providing a canonical text formatted representation of that log\nentry.\n\nThese permit simple log access code that prints log data into a terminal\n(or terminal-like view), like dbg, to continue using the String() call.\nIn fact, no changes had to be made to dbg for it to continue working,\neven though the API underneath changed.\n\nNaturally, raw logging entries continue to contain only a single line,\nso no change is implemented in the LineBuffer API. The containing\nLogEntry for raw log entries emits single-lined Strings() results and no\nnewline-containing strings in String() results.\n\nTest Plan: Updated unit tests to cover this.\n\nX-Origin-Diff: phab/D650\nGitOrigin-RevId: 4e339a930c4cbefff91b289b07bc31f774745eca\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "7b899a42363ac7b41a670359d30f38bc083bd973",
      "old_mode": 33188,
      "old_path": "core/pkg/logtree/BUILD.bazel",
      "new_id": "1498e07c1af7ecdb42baccc1ce2e72ce83daef04",
      "new_mode": 33188,
      "new_path": "core/pkg/logtree/BUILD.bazel"
    },
    {
      "type": "modify",
      "old_id": "caef97a59f785b5fd68704e5196a050ed57c5854",
      "old_mode": 33188,
      "old_path": "core/pkg/logtree/doc.go",
      "new_id": "ab3c537dd214117ec6124103e9ef1c849ddaacf3",
      "new_mode": 33188,
      "new_path": "core/pkg/logtree/doc.go"
    },
    {
      "type": "modify",
      "old_id": "253fc8ddc4545aa3ce53c14bc9466854ce32bec8",
      "old_mode": 33188,
      "old_path": "core/pkg/logtree/journal_test.go",
      "new_id": "474748aa851862bfeddf372312c7647947eb7e04",
      "new_mode": 33188,
      "new_path": "core/pkg/logtree/journal_test.go"
    },
    {
      "type": "modify",
      "old_id": "bb8a524312e44b11d350cf1bbf663e7d2c17d44b",
      "old_mode": 33188,
      "old_path": "core/pkg/logtree/logtree_access.go",
      "new_id": "770952622e23165e69d29a6bb7781d60f8b83b66",
      "new_mode": 33188,
      "new_path": "core/pkg/logtree/logtree_access.go"
    },
    {
      "type": "modify",
      "old_id": "c898012af0c99fb98107d142f5522a2ae68dadd6",
      "old_mode": 33188,
      "old_path": "core/pkg/logtree/logtree_publisher.go",
      "new_id": "190ef7e4c011145fa7b8f0624784496a3c5453a9",
      "new_mode": 33188,
      "new_path": "core/pkg/logtree/logtree_publisher.go"
    },
    {
      "type": "modify",
      "old_id": "f1465ad9a90363532f735556a0b52bafffb73229",
      "old_mode": 33188,
      "old_path": "core/pkg/logtree/logtree_test.go",
      "new_id": "b900201b3dffbceccf3e320291d0bc10f5bfbcdc",
      "new_mode": 33188,
      "new_path": "core/pkg/logtree/logtree_test.go"
    },
    {
      "type": "modify",
      "old_id": "ca7a0a0f4fb5e91bbf293c8cccd43663d06b43c4",
      "old_mode": 33188,
      "old_path": "core/pkg/logtree/payload.go",
      "new_id": "6338118e6e5358acc8347f3f7b914183b761f6eb",
      "new_mode": 33188,
      "new_path": "core/pkg/logtree/payload.go"
    },
    {
      "type": "delete",
      "old_id": "789fbcfddbebc854dc10088529a2c2ec8dbd8ed5",
      "old_mode": 33188,
      "old_path": "core/pkg/logtree/payload_test.go",
      "new_id": "0000000000000000000000000000000000000000",
      "new_mode": 0,
      "new_path": "/dev/null"
    },
    {
      "type": "modify",
      "old_id": "b0bbb57875add915af16bedf8eefe75838281062",
      "old_mode": 33188,
      "old_path": "core/proto/api/debug.proto",
      "new_id": "7a046ecd7f4a4cf6d5881840259c5695600452a8",
      "new_mode": 33188,
      "new_path": "core/proto/api/debug.proto"
    }
  ]
}
