├── .gitignore ├── .travis.yml ├── CHANGELOG ├── LICENSE ├── Readme.md ├── example ├── go.mod ├── go.sum └── main.go ├── example_test.go ├── glog.go ├── glog_test.go ├── go.mod └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - "1.11" 4 | 5 | env: 6 | - GO111MODULE=on 7 | 8 | script: 9 | - go test -v 10 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | ## 0.2.0 / 2018-09-23 2 | 3 | * [FEATURE] Simplify API by removing `DebugEnabled` method. 4 | 5 | ## 0.1.0 / 2018-09-22 6 | 7 | * [FEATURE] Add LoggerFunc, helper to create a Loggers without a new type. 8 | * [FEATURE] Add dummy implementation. 9 | * [FEATURE] Add noglog Logger interface and internal implementation. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [2018] [Spotahome Ltd.] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # noglog [![Build Status][travis-image]][travis-url] [![Go Report Card][goreport-image]][goreport-url] [![GoDoc][godoc-image]][godoc-url] 2 | 3 | noglog is a replacement for [github.com/golang/glog][glog] implementation. 4 | 5 | This package is a "bring you own" logger for glog replacement. It will replace all the glog calls with any logger that implements `noglog.Logger` interface. 6 | 7 | You can go from this: 8 | 9 | ```text 10 | ERROR: logging before flag.Parse: I0921 14:49:49.283733 1 leaderelection.go:175] attempting to acquire leader lease example-lock... 11 | ``` 12 | 13 | to this: 14 | 15 | ```text 16 | INFO[0000] attempting to acquire leader lease example-lock... source=k8s src="leaderelection.go:175" 17 | ``` 18 | 19 | or whatever format you want (or don't show at all). 20 | 21 | ## Features 22 | 23 | - Replace glog messages with your own logger (implement small interface and done). 24 | - No [flags] modification. 25 | 26 | ## Getting Started 27 | 28 | For a complete example, check [this][example] 29 | 30 | ### Import library 31 | 32 | First we need to add noglog as dependency, but it will need to be placed on `github.com/golang/glog` import path, so `github.com/slok/noglog` code replaces `github.com/golang/glog` 33 | 34 | #### Using go modules 35 | 36 | ```text 37 | require ( 38 | github.com/google/glog master 39 | ) 40 | 41 | replace ( 42 | github.com/google/glog => github.com/slok/noglog master 43 | ) 44 | ``` 45 | 46 | #### Using dep 47 | 48 | ```toml 49 | [[override]] 50 | name = "github.com/golang/glog" 51 | source = "github.com/slok/noglog" 52 | branch = "master" 53 | ``` 54 | 55 | ### Set our custom logger 56 | 57 | Import glog and the first thing that your app should do is instantiate your logger and set as the glog logger. Example: 58 | 59 | ```golang 60 | import ( 61 | "github.com/golang/glog" 62 | ) 63 | 64 | func main() { 65 | // Import custom logger that satisfies noglog.Logger interface. 66 | logger := mylogger.New() 67 | 68 | glog.SetLogger(logger) 69 | } 70 | ``` 71 | 72 | For security reasons if you don't set a logger, it will use a dummy logger that will disable Kubernetes logs. Sometimes this is useful also. 73 | Your custom logger needs to satisfy `noglog.Logger` interface. 74 | You have a helper if you want to create a logger using functions instead of creating a new type, `noglog.LoggerFunc`. 75 | 76 | This helper gives a lot of power to set up loggers easily. Some examples... 77 | 78 | Logrus: 79 | 80 | ```golang 81 | import ( 82 | "github.com/google/glog" 83 | "github.com/sirupsen/logrus" 84 | ) 85 | 86 | func main() { 87 | // Our app logger. 88 | logger := logrus.New() 89 | logger.SetLevel(logrus.DebugLevel) 90 | 91 | // Set our glog replacement. 92 | glog.SetLogger(&glog.LoggerFunc{ 93 | DebugfFunc: func(f string, a ...interface{}) { logger.Debugf(f, a...) }, 94 | InfofFunc: func(f string, a ...interface{}) { logger.Infof(f, a...) }, 95 | WarnfFunc: func(f string, a ...interface{}) { logger.Warnf(f, a...) }, 96 | ErrorfFunc: func(f string, a ...interface{}) { logger.Errorf(f, a...) }, 97 | }) 98 | 99 | glog.Info("I'm batman!") 100 | } 101 | ``` 102 | 103 | Example for zap: 104 | 105 | ```golang 106 | import ( 107 | "github.com/google/glog" 108 | "go.uber.org/zap" 109 | ) 110 | 111 | func main() { 112 | // Our app logger. 113 | logger, _ := zap.NewProduction() 114 | slogger := logger.Sugar() 115 | 116 | // Set our glog replacement. 117 | glog.SetLogger(&glog.LoggerFunc{ 118 | DebugfFunc: func(f string, a ...interface{}) { slogger.Debugf(f, a...) }, 119 | InfofFunc: func(f string, a ...interface{}) { slogger.Infof(f, a...) }, 120 | WarnfFunc: func(f string, a ...interface{}) { slogger.Warnf(f, a...) }, 121 | ErrorfFunc: func(f string, a ...interface{}) { slogger.Errorf(f, a...) }, 122 | }) 123 | 124 | glog.Info("I'm batman!") 125 | } 126 | ``` 127 | 128 | Example for zerolog: 129 | 130 | ```golang 131 | import ( 132 | "os" 133 | 134 | "github.com/google/glog" 135 | "github.com/rs/zerolog" 136 | ) 137 | 138 | func main() { 139 | // Our app logger. 140 | w := zerolog.ConsoleWriter{Out: os.Stderr} 141 | logger := zerolog.New(w).With().Timestamp().Logger() 142 | 143 | // Set our glog replacement. 144 | glog.SetLogger(&glog.LoggerFunc{ 145 | DebugfFunc: func(f string, a ...interface{}) { logger.Debug().Msgf(f, a...) }, 146 | InfofFunc: func(f string, a ...interface{}) { logger.Info().Msgf(f, a...) }, 147 | WarnfFunc: func(f string, a ...interface{}) { logger.Warn().Msgf(f, a...) }, 148 | ErrorfFunc: func(f string, a ...interface{}) { logger.Error().Msgf(f, a...) }, 149 | }) 150 | 151 | glog.Info("I'm batman!") 152 | } 153 | ``` 154 | 155 | ## Why 156 | 157 | Glog is a logger used on some important projects like Kubernetes, Glog modifies globals like `flag` of your program and it can't be done nothing to disable, modify... 158 | 159 | For example in Kubernetes glog is around all the source code, they don't use a common app logger interface that it can be reimplement with any log implementation, or pass any logger as dependency injection, so the Kubernetes extensions that use [client-go] will get flags modification, unstructured logs around it well set log format lines... 160 | 161 | ## When to use noglog 162 | 163 | - Tired of glog logs. 164 | - Every extension/app of Kubernetes I do has annoying unstructured logs. 165 | - My app flags have glog flags that I didn't ask for. 166 | - `ERROR: logging before flag.Parse: W0922` WTF when using a custom `flag.FlagSet`. 167 | 168 | ## Alternatives 169 | 170 | Although noglog can use any logger due to the simple interface, there are other alternatives that replace the logger for a specific logger with defaults, if you don't want to bring your own or customize these loggers here are the alternatives: 171 | 172 | - [glog-logrus] 173 | - [istio-glog](zap) 174 | 175 | [travis-image]: https://travis-ci.org/slok/noglog.svg?branch=master 176 | [travis-url]: https://travis-ci.org/slok/noglog 177 | [goreport-image]: https://goreportcard.com/badge/github.com/slok/noglog 178 | [goreport-url]: https://goreportcard.com/report/github.com/slok/noglog 179 | [godoc-image]: https://godoc.org/github.com/slok/noglog?status.svg 180 | [godoc-url]: https://godoc.org/github.com/slok/noglog 181 | [glog]: https://github.com/golang/glog 182 | [client-go]: https://github.com/kubernetes/client-go 183 | [flags]: https://golang.org/pkg/flag 184 | [glog-logrus]: https://github.com/kubermatic/glog-logrus 185 | [istio-glog]: https://github.com/istio/glog 186 | [example]: /example 187 | -------------------------------------------------------------------------------- /example/go.mod: -------------------------------------------------------------------------------- 1 | module example 2 | 3 | require ( 4 | github.com/google/glog v0.3.5-0.20180716071806-8d7a107d68c1 5 | github.com/rs/zerolog v1.9.1 6 | github.com/sirupsen/logrus v1.0.6 7 | github.com/slok/noglog v0.0.0-20180922095634-ef0d52ebfd8d // indirect 8 | go.uber.org/atomic v1.3.2 // indirect 9 | go.uber.org/multierr v1.1.0 // indirect 10 | go.uber.org/zap v1.9.1 11 | golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b // indirect 12 | golang.org/x/sys v0.0.0-20180921163948-d47a0f339242 // indirect 13 | ) 14 | 15 | replace github.com/google/glog => github.com/slok/noglog v0.1.1-0.20180923161859-ccca7a662ba9 16 | -------------------------------------------------------------------------------- /example/go.sum: -------------------------------------------------------------------------------- 1 | github.com/rs/zerolog v1.9.1 h1:AjV/SFRF0+gEa6rSjkh0Eji/DnkrJKVpPho6SW5g4mU= 2 | github.com/rs/zerolog v1.9.1/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 3 | github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s= 4 | github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= 5 | github.com/slok/noglog v0.0.0-20180922095634-ef0d52ebfd8d h1:v1vMg5M78Texj0QVKb5HKoGYD30U1RL55vQbHGXhIEs= 6 | github.com/slok/noglog v0.0.0-20180922095634-ef0d52ebfd8d/go.mod h1:TfKxwpEZPT+UA83bQ6RME146k0MM4e8mwHLf6bhcGDI= 7 | github.com/slok/noglog v0.1.1-0.20180923161859-ccca7a662ba9 h1:l+Xl3lbidQJCnQTi5278YVCEAYIpb9NPSocoYypYdd4= 8 | github.com/slok/noglog v0.1.1-0.20180923161859-ccca7a662ba9/go.mod h1:TfKxwpEZPT+UA83bQ6RME146k0MM4e8mwHLf6bhcGDI= 9 | go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= 10 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 11 | go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= 12 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 13 | go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= 14 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 15 | golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b h1:2b9XGzhjiYsYPnKXoEfL7klWZQIt8IfyRCz62gCqqlQ= 16 | golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 17 | golang.org/x/sys v0.0.0-20180921163948-d47a0f339242 h1:5DYsa+ZAwcJHjuY0Qet390sUr7qwkpnRsUNjddyc0b8= 18 | golang.org/x/sys v0.0.0-20180921163948-d47a0f339242/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 19 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/google/glog" 8 | "github.com/rs/zerolog" 9 | "github.com/sirupsen/logrus" 10 | "go.uber.org/zap" 11 | ) 12 | 13 | // stdLogger is the replacement for glog using our own 14 | // logging system. 15 | type stdLogger struct { 16 | debug bool 17 | } 18 | 19 | // Debugf satisfies glog.Logger interface. 20 | func (s *stdLogger) Debugf(format string, args ...interface{}) { 21 | if s.debug { 22 | fmt.Printf("[DEBUG] "+format, args...) 23 | } 24 | } 25 | 26 | // Infof satisfies glog.Logger interface. 27 | func (*stdLogger) Infof(format string, args ...interface{}) { 28 | fmt.Printf("[INFO] "+format, args...) 29 | } 30 | 31 | // Warnf satisfies glog.Logger interface. 32 | func (*stdLogger) Warnf(format string, args ...interface{}) { 33 | fmt.Printf("[WARN] "+format, args...) 34 | } 35 | 36 | // Errorf satisfies glog.Logger interface. 37 | func (*stdLogger) Errorf(format string, args ...interface{}) { 38 | fmt.Printf("[ERROR] "+format, args...) 39 | } 40 | 41 | func main() { 42 | loggerSetters := map[string]func() glog.Logger{ 43 | "std": func() glog.Logger { 44 | // Example using a type. 45 | return &stdLogger{debug: true} 46 | }, 47 | "logrus": func() glog.Logger { 48 | // Example using LoggerFunc. 49 | logger := logrus.New() 50 | logger.SetLevel(logrus.DebugLevel) 51 | return &glog.LoggerFunc{ 52 | DebugfFunc: func(f string, a ...interface{}) { logger.Debugf(f, a...) }, 53 | InfofFunc: func(f string, a ...interface{}) { logger.Infof(f, a...) }, 54 | WarnfFunc: func(f string, a ...interface{}) { logger.Warnf(f, a...) }, 55 | ErrorfFunc: func(f string, a ...interface{}) { logger.Errorf(f, a...) }, 56 | } 57 | }, 58 | "zap": func() glog.Logger { 59 | // Example using LoggerFunc. 60 | logger, _ := zap.NewProduction() 61 | slogger := logger.Sugar() 62 | return &glog.LoggerFunc{ 63 | DebugfFunc: func(f string, a ...interface{}) { slogger.Debugf(f, a...) }, 64 | InfofFunc: func(f string, a ...interface{}) { slogger.Infof(f, a...) }, 65 | WarnfFunc: func(f string, a ...interface{}) { slogger.Warnf(f, a...) }, 66 | ErrorfFunc: func(f string, a ...interface{}) { slogger.Errorf(f, a...) }, 67 | } 68 | }, 69 | "zerolog": func() glog.Logger { 70 | // Example using LoggerFunc. 71 | w := zerolog.ConsoleWriter{Out: os.Stderr} 72 | logger := zerolog.New(w).With().Timestamp().Logger() 73 | return &glog.LoggerFunc{ 74 | DebugfFunc: func(f string, a ...interface{}) { logger.Debug().Msgf(f, a...) }, 75 | InfofFunc: func(f string, a ...interface{}) { logger.Info().Msgf(f, a...) }, 76 | WarnfFunc: func(f string, a ...interface{}) { logger.Warn().Msgf(f, a...) }, 77 | ErrorfFunc: func(f string, a ...interface{}) { logger.Error().Msgf(f, a...) }, 78 | } 79 | }, 80 | } 81 | 82 | for name, f := range loggerSetters { 83 | fmt.Printf("\n---------%s----------\n\n", name) 84 | glog.SetLogger(f()) 85 | logWithGlog() 86 | fmt.Println() 87 | } 88 | } 89 | 90 | func logWithGlog() { 91 | glog.Info("I'm batman!") 92 | glog.InfoDepth(1, "I'm batman!") 93 | glog.Infoln("I'm batman!") 94 | glog.Infof("%s - %s", "I'm", "batman!") 95 | 96 | glog.Warning("I'm batman!") 97 | glog.WarningDepth(1, "I'm batman!") 98 | glog.Warningln("I'm batman!") 99 | glog.Warningf("%s - %s", "I'm", "batman!") 100 | 101 | glog.Error("I'm batman!") 102 | glog.ErrorDepth(1, "I'm batman!") 103 | glog.Errorln("I'm batman!") 104 | glog.Errorf("%s - %s", "I'm", "batman!") 105 | 106 | glog.V(2).Info("I'm batman!") 107 | glog.V(2).Infoln("I'm batman!") 108 | glog.V(2).Infof("%s - %s", "I'm", "batman!") 109 | 110 | // glog.Exit("I'm batman!") 111 | // glog.ExitDepth(1, "I'm batman!") 112 | // glog.Exitln("I'm batman!") 113 | // glog.Exitf("%s - %s", "I'm", "batman!") 114 | 115 | // glog.Fatal("I'm batman!") 116 | // glog.FatalDepth(1, "I'm batman!") 117 | // glog.Fatalln("I'm batman!") 118 | // glog.Fatalf("%s - %s", "I'm", "batman!") 119 | } 120 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package glog_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | glog "github.com/slok/noglog" 7 | ) 8 | 9 | // LoggerFunc shows how you would set a custom logger. In this case the LoggerFunc helper has been used, 10 | // so we don't need to create a new type for the example. But you could create a new type that satisfies 11 | // noglog.Logger interface. 12 | func Example_loggerFunc() { 13 | debug := false 14 | 15 | // Create our logger using the helper funcs so we don't need to create a new type. 16 | logger := &glog.LoggerFunc{ 17 | DebugfFunc: func(format string, args ...interface{}) { 18 | if debug { 19 | fmt.Printf("[DEBUG] "+format, args...) 20 | } 21 | }, 22 | InfofFunc: func(format string, args ...interface{}) { fmt.Printf("[INFO] "+format, args...) }, 23 | WarnfFunc: func(format string, args ...interface{}) { fmt.Printf("[WARN] "+format, args...) }, 24 | ErrorfFunc: func(format string, args ...interface{}) { fmt.Printf("[ERROR] "+format, args...) }, 25 | } 26 | 27 | // Set the custom logger 28 | glog.SetLogger(logger) 29 | 30 | // Test it. 31 | glog.Info("I'm batman!") 32 | glog.InfoDepth(1, "I'm batman!") 33 | glog.Infoln("I'm batman!") 34 | glog.Infof("%s - %s", "I'm", "batman!") 35 | 36 | glog.Warning("I'm batman!") 37 | glog.WarningDepth(1, "I'm batman!") 38 | glog.Warningln("I'm batman!") 39 | glog.Warningf("%s - %s", "I'm", "batman!") 40 | 41 | glog.Error("I'm batman!") 42 | glog.ErrorDepth(1, "I'm batman!") 43 | glog.Errorln("I'm batman!") 44 | glog.Errorf("%s - %s", "I'm", "batman!") 45 | 46 | // Without debug. 47 | glog.V(2).Info("I'm batman!") 48 | glog.V(2).Infoln("I'm batman!") 49 | glog.V(2).Infof("%s - %s", "I'm", "batman!") 50 | 51 | // With debug. 52 | debug = true 53 | glog.V(2).Info("I'm batman!") 54 | glog.V(2).Infoln("I'm batman!") 55 | glog.V(2).Infof("%s - %s", "I'm", "batman!") 56 | 57 | } 58 | -------------------------------------------------------------------------------- /glog.go: -------------------------------------------------------------------------------- 1 | // Package glog implements almost [glog](https://github.com/golang/glog) package API. 2 | // The aim of this package is to replace all the glog calls for the ones to a custom 3 | // logger that satisfies this package Logger interface. This way any code using glog 4 | // global logger will use the desired logger. 5 | package glog 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "sync" 11 | ) 12 | 13 | // Logger is the interface that a glog logger wrapper 14 | // needs to implement with the aim of replacing the logger that 15 | // comes with glog. 16 | type Logger interface { 17 | // Debugf logs with debug. 18 | Debugf(format string, args ...interface{}) 19 | // Infof logs with info. 20 | Infof(format string, args ...interface{}) 21 | // Warnf logs with warning. 22 | Warnf(format string, args ...interface{}) 23 | // Errorf logs with error. 24 | Errorf(format string, args ...interface{}) 25 | } 26 | 27 | // logger is the global logger that will intercept the glog calls 28 | // instead of calling glog it will use this logger. 29 | // By default it will be disabled for security reasons. 30 | var logger Logger = Dummy 31 | 32 | var mu = sync.Mutex{} 33 | 34 | // SetLogger sets the glog replacement logger. 35 | func SetLogger(l Logger) { 36 | mu.Lock() 37 | defer mu.Unlock() 38 | logger = l 39 | } 40 | 41 | // Level replacement for glog. 42 | type Level int32 43 | 44 | // Verbose replacement for glog. 45 | type Verbose bool 46 | 47 | // Flush replacement for glog. 48 | func Flush() {} 49 | 50 | // V replacement for glog. 51 | func V(_ Level) Verbose { 52 | return Verbose(false) // Doesn't mind. 53 | } 54 | 55 | // Info replacement for glog. 56 | func (Verbose) Info(args ...interface{}) { 57 | s := fmt.Sprint(args...) 58 | logger.Debugf(s) 59 | } 60 | 61 | // Infoln replacement for glog. 62 | func (v Verbose) Infoln(args ...interface{}) { 63 | args = append(args, "\n") 64 | v.Info(args...) 65 | } 66 | 67 | // Infof replacement for glog. 68 | func (Verbose) Infof(format string, args ...interface{}) { 69 | logger.Debugf(format, args...) 70 | } 71 | 72 | // Info replacement for glog. 73 | func Info(args ...interface{}) { 74 | s := fmt.Sprint(args...) 75 | logger.Infof(s) 76 | } 77 | 78 | // InfoDepth replacement for glog. 79 | func InfoDepth(_ int, args ...interface{}) { 80 | Info(args...) 81 | } 82 | 83 | // Infoln replacement for glog. 84 | func Infoln(args ...interface{}) { 85 | args = append(args, "\n") 86 | Info(args...) 87 | } 88 | 89 | // Infof replacement for glog. 90 | func Infof(format string, args ...interface{}) { 91 | logger.Infof(format, args...) 92 | } 93 | 94 | // Warning replacement for glog. 95 | func Warning(args ...interface{}) { 96 | s := fmt.Sprint(args...) 97 | logger.Warnf(s) 98 | } 99 | 100 | // WarningDepth replacement for glog. 101 | func WarningDepth(_ int, args ...interface{}) { 102 | Warning(args...) 103 | } 104 | 105 | // Warningln replacement for glog. 106 | func Warningln(args ...interface{}) { 107 | args = append(args, "\n") 108 | Warning(args...) 109 | } 110 | 111 | // Warningf replacement for glog. 112 | func Warningf(format string, args ...interface{}) { 113 | logger.Warnf(format, args...) 114 | } 115 | 116 | // Error replacement for glog. 117 | func Error(args ...interface{}) { 118 | s := fmt.Sprint(args...) 119 | logger.Errorf(s) 120 | } 121 | 122 | // ErrorDepth replacement for glog. 123 | func ErrorDepth(_ int, args ...interface{}) { 124 | Error(args...) 125 | } 126 | 127 | // Errorln replacement for glog. 128 | func Errorln(args ...interface{}) { 129 | args = append(args, "\n") 130 | Error(args...) 131 | } 132 | 133 | // Errorf replacement for glog. 134 | func Errorf(format string, args ...interface{}) { 135 | logger.Errorf(format, args...) 136 | } 137 | 138 | // Fatal replacement for glog. 139 | func Fatal(args ...interface{}) { 140 | Error(args...) 141 | os.Exit(255) 142 | } 143 | 144 | // FatalDepth replacement for glog. 145 | func FatalDepth(depth int, args ...interface{}) { 146 | ErrorDepth(depth, args...) 147 | os.Exit(255) 148 | } 149 | 150 | // Fatalln replacement for glog. 151 | func Fatalln(args ...interface{}) { 152 | Errorln(args...) 153 | os.Exit(255) 154 | } 155 | 156 | // Fatalf replacement for glog. 157 | func Fatalf(format string, args ...interface{}) { 158 | Errorf(format, args...) 159 | os.Exit(255) 160 | } 161 | 162 | // Exit replacement for glog. 163 | func Exit(args ...interface{}) { 164 | Error(args...) 165 | os.Exit(1) 166 | } 167 | 168 | // ExitDepth replacement for glog. 169 | func ExitDepth(depth int, args ...interface{}) { 170 | ErrorDepth(depth, args...) 171 | os.Exit(1) 172 | } 173 | 174 | // Exitln replacement for glog. 175 | func Exitln(args ...interface{}) { 176 | Errorln(args...) 177 | os.Exit(1) 178 | } 179 | 180 | // Exitf replacement for glog. 181 | func Exitf(format string, args ...interface{}) { 182 | Errorf(format, args...) 183 | os.Exit(1) 184 | } 185 | 186 | // LoggerFunc is a logger that satisfies Logger interface and 187 | // gets the Logger interface required methods as func fields. 188 | // Basically is a helper to not create a custom type. 189 | type LoggerFunc struct { 190 | // DebugfFunc is a function for DebugfFunc `Logger.Debugf(format string, args ...interface{})`. 191 | DebugfFunc func(format string, args ...interface{}) 192 | // InfofFunc is a function for InfofFunc `Logger.Infof(format string, args ...interface{})`. 193 | InfofFunc func(format string, args ...interface{}) 194 | // WarnfFunc is a function for WarnfFunc `Logger.Warnf(format string, args ...interface{})`. 195 | WarnfFunc func(format string, args ...interface{}) 196 | // ErrorfFunc is a function for ErrorfFunc `Logger.Errorf(format string, args ...interface{})`. 197 | ErrorfFunc func(format string, args ...interface{}) 198 | } 199 | 200 | // Debugf satisfies Logger interface. 201 | func (l *LoggerFunc) Debugf(format string, args ...interface{}) { l.DebugfFunc(format, args...) } 202 | 203 | // Infof satisfies Logger interface. 204 | func (l *LoggerFunc) Infof(format string, args ...interface{}) { l.InfofFunc(format, args...) } 205 | 206 | // Warnf satisfies Logger interface. 207 | func (l *LoggerFunc) Warnf(format string, args ...interface{}) { l.WarnfFunc(format, args...) } 208 | 209 | // Errorf satisfies Logger interface. 210 | func (l *LoggerFunc) Errorf(format string, args ...interface{}) { l.ErrorfFunc(format, args...) } 211 | 212 | // Dummy is a dummy logger useful for tests and disabling logging. 213 | var Dummy = &LoggerFunc{ 214 | DebugfFunc: func(format string, args ...interface{}) {}, 215 | InfofFunc: func(format string, args ...interface{}) {}, 216 | WarnfFunc: func(format string, args ...interface{}) {}, 217 | ErrorfFunc: func(format string, args ...interface{}) {}, 218 | } 219 | -------------------------------------------------------------------------------- /glog_test.go: -------------------------------------------------------------------------------- 1 | package glog_test 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "testing" 7 | 8 | glog "github.com/slok/noglog" 9 | ) 10 | 11 | type mockLogger struct { 12 | debug bool 13 | rw bytes.Buffer 14 | } 15 | 16 | func (m *mockLogger) Debugf(format string, args ...interface{}) { 17 | if m.debug { 18 | s := fmt.Sprintf(format, args...) 19 | m.rw.WriteString("debugf: " + s) 20 | } 21 | } 22 | func (m *mockLogger) Infof(format string, args ...interface{}) { 23 | s := fmt.Sprintf(format, args...) 24 | m.rw.WriteString("infof: " + s) 25 | } 26 | func (m *mockLogger) Warnf(format string, args ...interface{}) { 27 | s := fmt.Sprintf(format, args...) 28 | m.rw.WriteString("warnf: " + s) 29 | } 30 | func (m *mockLogger) Errorf(format string, args ...interface{}) { 31 | s := fmt.Sprintf(format, args...) 32 | m.rw.WriteString("errorf: " + s) 33 | } 34 | 35 | // TestLogger will test the glog replaced logger. This tests uses globals don't run in parallel. 36 | func TestLogger(t *testing.T) { 37 | tests := []struct { 38 | name string 39 | enableDebug bool 40 | glogActions func() 41 | expLog string 42 | }{ 43 | { 44 | name: "Info.", 45 | glogActions: func() { 46 | glog.Info("I'm Batman!") 47 | }, 48 | expLog: "infof: I'm Batman!", 49 | }, 50 | { 51 | name: "InfoDepth.", 52 | glogActions: func() { 53 | glog.InfoDepth(0, "I'm Batman!") 54 | }, 55 | expLog: "infof: I'm Batman!", 56 | }, 57 | { 58 | name: "Infoln.", 59 | glogActions: func() { 60 | glog.Infoln("I'm Batman!") 61 | }, 62 | expLog: "infof: I'm Batman!\n", 63 | }, 64 | { 65 | name: "Infof.", 66 | glogActions: func() { 67 | glog.Infof("%s %s", "I'm", "Batman!") 68 | }, 69 | expLog: "infof: I'm Batman!", 70 | }, 71 | 72 | { 73 | name: "Warning.", 74 | glogActions: func() { 75 | glog.Warning("I'm Batman!") 76 | }, 77 | expLog: "warnf: I'm Batman!", 78 | }, 79 | { 80 | name: "WarningDepth.", 81 | glogActions: func() { 82 | glog.WarningDepth(0, "I'm Batman!") 83 | }, 84 | expLog: "warnf: I'm Batman!", 85 | }, 86 | { 87 | name: "Warningln.", 88 | glogActions: func() { 89 | glog.Warningln("I'm Batman!") 90 | }, 91 | expLog: "warnf: I'm Batman!\n", 92 | }, 93 | { 94 | name: "Warningf.", 95 | glogActions: func() { 96 | glog.Warningf("%s %s", "I'm", "Batman!") 97 | }, 98 | expLog: "warnf: I'm Batman!", 99 | }, 100 | 101 | { 102 | name: "Error.", 103 | glogActions: func() { 104 | glog.Error("I'm Batman!") 105 | }, 106 | expLog: "errorf: I'm Batman!", 107 | }, 108 | { 109 | name: "ErrorDepth.", 110 | glogActions: func() { 111 | glog.ErrorDepth(0, "I'm Batman!") 112 | }, 113 | expLog: "errorf: I'm Batman!", 114 | }, 115 | { 116 | name: "Errorln.", 117 | glogActions: func() { 118 | glog.Errorln("I'm Batman!") 119 | }, 120 | expLog: "errorf: I'm Batman!\n", 121 | }, 122 | { 123 | name: "Errorf.", 124 | glogActions: func() { 125 | glog.Errorf("%s %s", "I'm", "Batman!") 126 | }, 127 | expLog: "errorf: I'm Batman!", 128 | }, 129 | 130 | { 131 | name: "Verbose Info (disabled).", 132 | glogActions: func() { 133 | glog.V(2).Info("I'm Batman!") 134 | }, 135 | expLog: "", 136 | }, 137 | { 138 | name: "Verbose Infoln (disabled).", 139 | glogActions: func() { 140 | glog.V(2).Infoln("I'm Batman!") 141 | }, 142 | expLog: "", 143 | }, 144 | { 145 | name: "Verbose Infof (disabled).", 146 | glogActions: func() { 147 | glog.V(2).Infof("%s %s", "I'm", "Batman!") 148 | }, 149 | expLog: "", 150 | }, 151 | { 152 | name: "Verbose Info (enabled).", 153 | enableDebug: true, 154 | glogActions: func() { 155 | glog.V(2).Info("I'm Batman!") 156 | }, 157 | expLog: "debugf: I'm Batman!", 158 | }, 159 | { 160 | name: "Verbose Infoln (enabled).", 161 | enableDebug: true, 162 | glogActions: func() { 163 | glog.V(2).Infoln("I'm Batman!") 164 | }, 165 | expLog: "debugf: I'm Batman!\n", 166 | }, 167 | { 168 | name: "Verbose Infof (enabled).", 169 | enableDebug: true, 170 | glogActions: func() { 171 | glog.V(2).Infof("%s %s", "I'm", "Batman!") 172 | }, 173 | expLog: "debugf: I'm Batman!", 174 | }, 175 | } 176 | 177 | for _, test := range tests { 178 | t.Run(test.name, func(t *testing.T) { 179 | ml := &mockLogger{ 180 | debug: test.enableDebug, 181 | } 182 | glog.SetLogger(ml) 183 | test.glogActions() 184 | 185 | gotLog := ml.rw.String() 186 | if test.expLog != gotLog { 187 | t.Errorf("expected log doesn't match: \n exp: %s\n got: %s", test.expLog, gotLog) 188 | } 189 | }) 190 | } 191 | } 192 | 193 | func TestLoggerFunc(t *testing.T) { 194 | tests := []struct { 195 | name string 196 | enableDebug bool 197 | glogActions func() 198 | expLog string 199 | }{ 200 | { 201 | name: "Info.", 202 | glogActions: func() { 203 | glog.Info("I'm Batman!") 204 | }, 205 | expLog: "infof: I'm Batman!", 206 | }, 207 | { 208 | name: "Warning.", 209 | glogActions: func() { 210 | glog.Warning("I'm Batman!") 211 | }, 212 | expLog: "warnf: I'm Batman!", 213 | }, 214 | { 215 | name: "Error.", 216 | glogActions: func() { 217 | glog.Error("I'm Batman!") 218 | }, 219 | expLog: "errorf: I'm Batman!", 220 | }, 221 | { 222 | name: "Verbose Info (disabled).", 223 | glogActions: func() { 224 | glog.V(2).Info("I'm Batman!") 225 | }, 226 | expLog: "", 227 | }, 228 | { 229 | name: "Verbose Info (enabled).", 230 | enableDebug: true, 231 | glogActions: func() { 232 | glog.V(2).Info("I'm Batman!") 233 | }, 234 | expLog: "debugf: I'm Batman!", 235 | }, 236 | } 237 | 238 | for _, test := range tests { 239 | t.Run(test.name, func(t *testing.T) { 240 | ml := &mockLogger{debug: test.enableDebug} 241 | 242 | // Create our logger using funcs. 243 | mlf := &glog.LoggerFunc{ 244 | DebugfFunc: ml.Debugf, 245 | InfofFunc: ml.Infof, 246 | WarnfFunc: ml.Warnf, 247 | ErrorfFunc: ml.Errorf, 248 | } 249 | 250 | glog.SetLogger(mlf) 251 | test.glogActions() 252 | 253 | gotLog := ml.rw.String() 254 | if test.expLog != gotLog { 255 | t.Errorf("expected log doesn't match: \n exp: %s\n got: %s", test.expLog, gotLog) 256 | } 257 | }) 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/slok/noglog 2 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slok/noglog/470afb9f333a2db93161d95ed1ae9a359b9eb67c/go.sum --------------------------------------------------------------------------------