{"action":"created","issue":{"url":"https://api.github.com/repos/golang/go/issues/13182","labels_url":"https://api.github.com/repos/golang/go/issues/13182/labels{/name}","comments_url":"https://api.github.com/repos/golang/go/issues/13182/comments","events_url":"https://api.github.com/repos/golang/go/issues/13182/events","html_url":"https://github.com/golang/go/issues/13182","id":115657088,"number":13182,"title":"proposal: add SetOutputFn to log.Logger","user":{"login":"srinathh","id":2973973,"avatar_url":"https://avatars.githubusercontent.com/u/2973973?v=3","gravatar_id":"","url":"https://api.github.com/users/srinathh","html_url":"https://github.com/srinathh","followers_url":"https://api.github.com/users/srinathh/followers","following_url":"https://api.github.com/users/srinathh/following{/other_user}","gists_url":"https://api.github.com/users/srinathh/gists{/gist_id}","starred_url":"https://api.github.com/users/srinathh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/srinathh/subscriptions","organizations_url":"https://api.github.com/users/srinathh/orgs","repos_url":"https://api.github.com/users/srinathh/repos","events_url":"https://api.github.com/users/srinathh/events{/privacy}","received_events_url":"https://api.github.com/users/srinathh/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/golang/go/labels/Proposal","name":"Proposal","color":"ededed"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/golang/go/milestones/30","html_url":"https://github.com/golang/go/milestones/Proposal","labels_url":"https://api.github.com/repos/golang/go/milestones/30/labels","id":1373555,"number":30,"title":"Proposal","description":"Proposals that are pending (not yet accepted/rejected).\r\n","creator":{"login":"rsc","id":104030,"avatar_url":"https://avatars.githubusercontent.com/u/104030?v=3","gravatar_id":"","url":"https://api.github.com/users/rsc","html_url":"https://github.com/rsc","followers_url":"https://api.github.com/users/rsc/followers","following_url":"https://api.github.com/users/rsc/following{/other_user}","gists_url":"https://api.github.com/users/rsc/gists{/gist_id}","starred_url":"https://api.github.com/users/rsc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rsc/subscriptions","organizations_url":"https://api.github.com/users/rsc/orgs","repos_url":"https://api.github.com/users/rsc/repos","events_url":"https://api.github.com/users/rsc/events{/privacy}","received_events_url":"https://api.github.com/users/rsc/received_events","type":"User","site_admin":false},"open_issues":32,"closed_issues":14,"state":"open","created_at":"2015-10-24T01:40:49Z","updated_at":"2015-12-28T19:24:23Z","due_on":null,"closed_at":null},"comments":7,"created_at":"2015-11-07T10:11:07Z","updated_at":"2015-12-29T15:12:21Z","closed_at":null,"body":"## Motivation\r\nGo stdlib provides a `log.Logger` that is widely used in both Go programs and Go libraries (eg. most notably in `http.Server`) as a standardized logging component. \r\n\r\nHowever, the current implementation of the `log.Logger` enforces a specific logging format with limited flexibility which requires text parsing to allow it to be connected to any other logging system implementation through the swappable `io.Writer` interface. This adds complexity and overhead. The other alternative of directly using third party logging libraries is not very scalable both because existing libraries including components like `http.Server` in the stdlib expect `log.Logger` and because of network effects of stdlib.\r\n\r\n## Proposal\r\nThis proposes a minor change to the log package to make `log.Logger` more extensible in a fully backwards compatible by allowing `Logger.Output()` to write logs using custom logging implementations. \r\n\r\nWe do this by defining a function type called `OutputFn` with the same function signature as the current `Logger.Output()` and introducing an unexported field `outputfn` in `Logger` to hold the function that should be used for output much like we use the `out` field to hold the `io.Writer` currently. By default, `log.New()` will set the `outputfn` to the  current implementation which is moved to `Logger.DefOutputFn()`. This can be swapped to any other `OutputFn` implementation by calling `Logger.SetOutputFn()` in the same way as we currently can swap `io.Writer` by calling `Logger.SetOutput()`\r\n\r\nFor the top level `log` package, we provide `log.SetOutputFn()` and `log.SetDefOutputFn()` to set the `OutputFn` of the `log.std` logger and reset it to default.\r\n\r\n## Proof of Concept\r\nI have implemented a [proof of concept](https://github.com/srinathh/log) for this proposed change and added [an example](https://github.com/srinathh/log/blob/master/customlogger_test.go) in the test suite that demonstrates logging to a Tab Separated Variable format. While in the example i am merely writing to a Writer, the Output could be to anything including over the network etc.\r\n\r\nIf this approach looks ok, I can package this into a CL incorporating any feedback.\r\n\r\n## Rationale for the Approach\r\nMost of the actual work of logging happens in `Logger.Output()` (and in the unexported `Logger.formatHeader()` called by it) which makes it a prime candidate for flexibility. We cannot change `log.Logger` into an interface due to Go1 compatibility promise and this approach therefore allows a lot of flexibility with a very minor change."},"comment":{"url":"https://api.github.com/repos/golang/go/issues/comments/167807919","html_url":"https://github.com/golang/go/issues/13182#issuecomment-167807919","issue_url":"https://api.github.com/repos/golang/go/issues/13182","id":167807919,"user":{"login":"rsc","id":104030,"avatar_url":"https://avatars.githubusercontent.com/u/104030?v=3","gravatar_id":"","url":"https://api.github.com/users/rsc","html_url":"https://github.com/rsc","followers_url":"https://api.github.com/users/rsc/followers","following_url":"https://api.github.com/users/rsc/following{/other_user}","gists_url":"https://api.github.com/users/rsc/gists{/gist_id}","starred_url":"https://api.github.com/users/rsc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rsc/subscriptions","organizations_url":"https://api.github.com/users/rsc/orgs","repos_url":"https://api.github.com/users/rsc/repos","events_url":"https://api.github.com/users/rsc/events{/privacy}","received_events_url":"https://api.github.com/users/rsc/received_events","type":"User","site_admin":false},"created_at":"2015-12-29T15:12:21Z","updated_at":"2015-12-29T15:12:21Z","body":"With the exception of file name, you can shorten to:\r\n - SetFlags(0), SetPrefix(\"\")\r\n - call SetOutput(w)\r\n - w.Write gets just the log message and can add whatever prefix or formatting it wants, without any parsing\r\n\r\nIf you want file names, then yes you have to use SetFlags(Llongfile) or Lshortfile and parse the file name. That's unfortunate, but it doesn't seem worth a whole new API. If we were starting over then yes I think we might reasonably make SetOutput take a func and have a separate SetWriter. But we're not starting over. We're working with what we have. If we created new API every time we realized we could have done something differently, we'd end up with a much larger (and arguably bloated) standard library. The bar is very high for additions."}}