搭建gos

Assigning loggers to package-level variables is an anti-pattern. When you declare var log = mylogger.New() in the package namespace, you create a tight compile-time dependency on the particular brand of logger you use. It makes your program brittle, hard to change.

将记录器分配给程序包级变量是一种反模式 。 在包名称空间中声明var log = mylogger.New() ,将对所使用的特定记录器品牌产生紧密的编译时依赖性。 它使您的程序脆弱,难以更改。

The solution is to pass an interface that describes the capabilities of a compatible logger but ignores its identity until runtime. But what does that look like? Specifically, what does it look like when you want to pass a logger to a function whose signature is not under your control?

解决方案是传递一个描述兼容记录器功能的接口,但忽略其身份,直到运行时。 但是那是什么样子? 具体来说,当您要将记录器传递给签名不受您控制的功能时,它看起来像什么?

The http.HandlerFunc is a type where logging is essential but unintuitive:

http.HandlerFunc是日志记录必不可少但不直观的一种类型:

type HandlerFunc(ResponseWriter, *Request)

Confronted with this signature, a package-level logger that you can access from inside the HandlerFunc seems like an easy solution, but it’ll come back to bite you as your program evolves. Our mission: to inject a logging interface into something that looks and behaves like the mighty HandlerFunc.

面对此签名,您可以从HandlerFunc内部访问的程序包级记录器似乎是一个简单的解决方案,但随着程序的发展,它会再次对您造成影响。 我们的任务是:向外观和行为类似于强大的HandlerFunc注入日志记录接口。

建立自己的HandlerFactory (Build your own HandlerFactory)

First up, the type declarations:

首先,类型声明:

package routingimport ("errors""net/http""github.com/gorilla/mux"
)type logger interface {Printf(format string, v ...interface{})
}type loggingHandlerFunc = func(w http.ResponseWriter, r *http.Request, l logger)type loggingHandler struct {loggerhandlerFunc loggingHandlerFunc
}

The interface logger defines what any logger we choose to inject must be capable of, in this case, Printf. The concrete type of the logger is unimportant; we only care about what it can do.

接口logger定义了我们选择注入的任何记录器必须具备的功能,在这种情况下,该功能是Printf 。 记录器的具体类型并不重要; 我们只关心它能做什么。

loggingHandlerFunc is the centrepiece of this solution — a type that looks a lot like http.HandlerFunc but which also accepts an argument that implements our logger interface.

loggingHandlerFunc是此解决方案的核心-一种看起来很像http.HandlerFunc的类型,但它也接受实现我们的logger接口的参数。

But how do we “forward” an incoming *http.Request to a loggingHandlerFunc? That’s what loggingHandler does. loggingHandler embeds both a logger and a loggingHandlerFunc, and defines a familiar method:

但是,我们如何将传入的*http.RequestloggingHandlerFunc ? 那就是loggingHandler所做的。 loggingHandler嵌入了loggerloggingHandlerFunc ,并定义了一个熟悉的方法:

func (lh *loggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {lh.handlerFunc(w, r, lh.logger)
}

Thus, our loggingHandler implements http.Handler, which requires the single method ServeHTTP(w http.ResponseWriter, r *http.Request). We can now pass a *loggingHandler to an http.ServeMux (or any mux package of your choice), and traffic to the route you specify will be passed through the *loggingHandler to the embedded loggingHandlerFunc, picking up a logger along the way.

因此,我们的loggingHandler实现了http.Handler ,它需要单个方法ServeHTTP(w http.ResponseWriter, r *http.Request) 。 现在,我们可以将*loggingHandler传递给http.ServeMux (或您选择的任何多路复用器包),并且指定路由的流量将通过*loggingHandler传递给嵌入式loggingHandlerFunc ,并沿途选择一个logger

func homepageHandler(w http.ResponseWriter, r *http.Request, log logger) {err := errors.New("This will be logged")log.Printf("%-8s %s: %v", "INFO", "homepageHandler", err)http.Error(w, http.StatusText(http.StatusInternalServerError),http.StatusInternalServerError)
}

However, this approach leads to a lot of manual *loggingHandler creation, and in the likely event that you want to use the same logger across a number of routes, you’ll find yourself repeatedly constructing *loggingHandlers with similar inputs. Let’s streamline this with a factory.

但是,这种方法会导致大量手动*loggingHandler创建,并且在可能要跨多个路径使用同一logger的可能情况下,您会发现自己反复构造具有相似输入的*loggingHandler 。 让我们用工厂简化它。

func loggingHandlerFactory(l logger) func(loggingHandlerFunc) *loggingHandler {return func(hf loggingHandlerFunc) *loggingHandler {return &loggingHandler{l, hf}}
}func Router(l logger) *mux.Router {router := mux.NewRouter()withLogger := loggingHandlerFactory(l)router.Handle("/", withLogger(homepageHandler)).Methods(http.MethodGet)return router
}

loggingHandlerFactory takes in a logger and returns a closure that, when called with a loggingHandlerFunc, returns a new *loggingHandler with the correct logger baked in.

loggingHandlerFactory接受一个logger并返回一个闭包,当使用loggingHandlerFunc调用该闭包时,将返回一个新的*loggingHandler其中包含正确的logger。

Using a loggingHandlerFunc in a route becomes as simple as passing it to the factory. Better yet, the loggingHandlerFuncs you write are embeddable in whatever struct you like, not just the loggingHandler defined here. This configuration is easy to change and has no knock-on effects outside of the package.

在路由中使用loggingHandlerFunc就像将其传递给工厂一样简单。 更好的是,您编写的loggingHandlerFunc可以嵌入到您喜欢的任何结构中,而不仅仅是loggingHandler定义的loggingHandler 。 此配置易于更改,在包装外部没有任何连锁效应。

That contrasts somewhat with an approach that’s more straightforward but may restrict your freedom to change:

这与更简单但可能会限制您进行更改的自由的方法形成鲜明对比:

type logger interface {Printf(format string, v ...interface{})
}type loggingHandler struct {logger
}func Router(l logger) *mux.Router {router := mux.NewRouter()lh := &loggingHandler{l}router.HandleFunc("/", lh.homepageHandler).Methods(http.MethodGet)return router
}func (lh *loggingHandler) homepageHandler(w http.ResponseWriter, r *http.Request) {err := errors.New("This will be logged")lh.Printf("%-8s %s: %v", "INFO", "homepageHandler", err)http.Error(w, http.StatusText(http.StatusInternalServerError),http.StatusInternalServerError)
}

Here, the loggingHandler embeds only a logger, and plain old http.HandlerFuncs are declared as methods on *loggingHandler, giving them access to its logger field.

在这里, loggingHandler仅嵌入一个logger,而普通的旧http.HandlerFunc声明为*loggingHandler上的方法,从而使他们可以访问其logger字段。

I find this easier to intuit, but it binds your http.HandlerFuncs to a single implementation of loggingHandler. If the loggingHandler has to change, it could impact every HandlerFunc attached to it. Contrast this with the first approach, where a loggingHandlerFunc doesn’t care where its logger comes from, only that it’s passed as an argument. It ensures that our package is not just loosely coupled to the outside world, it’s loosely coupled inside too.

我觉得这是比较容易忒,但它结合你的http.HandlerFunc s到单个实现loggingHandler 。 如果loggingHandler必须更改,则可能会影响附加到它的每个HandlerFunc 。 与第一种方法,其中一个对比这loggingHandlerFunc不关心那里logger从何而来,只是它作为参数传递。 它确保我们的包装不仅与外界松散耦合,而且也与内部松散耦合。

Here’s the example in full.

这是完整的示例 。

荣誉(?)提及 (An Honourable(?) Mention)

There’s one school of thought that suggests you could stash error events in the Values of a handlerFunc's request Context. When your http.HandlerFuncs return, the one at the top of the chain would be responsible for getting them out again and logging a unified report about everything that happened during the request.

有一种想法建议您可以将错误事件存储在handlerFunc的request ContextValue 。 当您的http.HandlerFunc返回时,位于链顶部的那个将负责再次将其释放,并记录有关请求期间发生的所有事件的统一报告。

There’s another school that would have me hunted for suggesting it to you.

还有另一所学校会想我向您推荐它。

The first contention is that Values is an amorphous sack of interface{}: interface{} pairs that invite a wealth of lurking bugs through the type assertions required to get data out again. The second is that having this bag of formless data persist for the lifetime of the request amounts to thread-local storage, which is inimical to the Go concurrency model.

第一个争论是Valuesinterface{}: interface{}的无定形麻袋interface{}: interface{}对通过再次获取数据所需的类型断言引发大量潜伏的bug。 第二个问题是,在请求的生命周期内保留这袋无格式数据将构成线程本地存储,这对Go并发模型不利 。

Nevertheless, if you’re curious about how such heresy would be implemented (I know, you’re asking for a friend), Peter Bourgon’s ctxdata is the code to see.

但是,如果您对如何实现这样的异端感到好奇(我知道,您是在找一个朋友), 那么可以看一下Peter Bourgon的ctxdata 。

The debate surrounding logging in Go is fascinating (no, really). I highly recommend catching up on it.

有关登录Go的争论很有趣(不,真的)。 我强烈建议赶上它。

Thanks go to Dave Cheney and Peter Bourgon for their help in wrapping my head around this.

感谢Dave Cheney和Peter Bourgon对我的帮助。

翻译自: https://medium.com/@angusmorrison/how-to-inject-a-logger-into-gos-http-handlers-34481a4f2aad

搭建gos

http://www.taodudu.cc/news/show-2675611.html

相关文章:

  • Go使用gos7实现西门子PLC通讯
  • Gos —— 加载内核
  • SAP-ABAP 读取billing document以及其它订单附件的实例(GOS)
  • Gos —— 获取物理内存容量
  • Gos —— shell程序
  • 【整理】GOS附件的上传与下载
  • SAP GOS cl_gos_manager 添加附件功能
  • Gos —— 搭建基础环境
  • Gos ——操作键盘
  • Gos —— 实现线程和进程
  • Gos ——内存管理系统
  • Gos —— 开启保护模式
  • Gos —— 文件系统
  • Gos —— 显示器控制
  • Gos —— 掌控硬盘
  • Gos —— 开启中断与中断机制详解
  • 以太坊之dapp例子
  • 记录以太坊节点安装
  • 以太坊 solidity msg对象
  • 以太坊的未来
  • 以太坊发展规划
  • 以太坊网络重启并开启rpc
  • 以太坊源码解读
  • 以太坊地址生成过程
  • 图解以太坊交易
  • Polygon与以太坊通信机制研究
  • 以太坊Ghost协议
  • 以太坊智能合约开发语言 - Solidity
  • 以太坊基本概念
  • 以太坊之Gas

搭建gos_如何将记录器注入gos http处理程序相关推荐

  1. ssh 框架引入service_搭建SSH开发框架时autowired注入为空的问题

    最近在搭建SSH框架,使用@Autowired自动装配时,需要注入的对象是空,表明注入失败. 尝试了很多次还是不行,现在感觉可能是spring没配置好,所以类里的注解写对也注入不进去.但是从log4j ...

  2. putty串口打开没反应_如何使用树莓派快速搭建一个串口数据记录器?

    在最近发现同事的某些项目临时增加了一些需求,把测出的能见度数据保存在存储介质中,并且可以随时远程查阅.如果在项目时间与成本允许的情况下,我们会选择在PCB中增加SD卡槽以及以太网接口,用于存储数据和联 ...

  3. 绕安全狗mysql_技术讨论 | Fuzz绕过安全狗4.0实现SQL注入

    0×00 前言 本文使用了burp的intruder模块进行fuzz,并修改了sqlmap工具的tamper脚本,对安全狗进行绕过. 0×01注入绕waf过常用手法使用大小写绕过 使用/**/注释符绕 ...

  4. 渗透测试-注入攻击专题

    渗透测试- 注入 Neo4j ACCESS ORM注入 SSTI 服务器端模板注入(Server-Side Template Injection) 万能密码 漏洞介绍 测试方法 sql手工注入 @ap ...

  5. 将经过身份验证的用户注入Spring MVC @Controllers

    可以使用@AuthenticationPrincipal批注和AuthenticationPrincipalArgumentResolver这是Spring MVS MethodArgumentRes ...

  6. Java中的记录器 - Java日志示例

    Java中的记录器 - Java日志示例 今天我们将研究Java中的Logger.Java Logger提供了java编程的日志记录. 目录[ 隐藏 ] 1 Java中的记录器 1.1 Java Lo ...

  7. java 记录考勤记录_Java中的记录器– Java记录示例

    java 记录考勤记录 Today we will look into Logger in Java. Java Logger provides logging in java programming ...

  8. 异常解决——Spring Cloud FeignClient: BeanCreationException: Error creating bean with

    最近自己搭建了Spring Cloud 架构,在做客户端的时候,FeignClient标注的Service接口 无法注入,can not be autowired . 网上找了一堆资料也没发现可用的. ...

  9. 在ASP.NET Core中创建基于Quartz.NET托管服务轻松实现作业调度

    在这篇文章中,我将介绍如何使用ASP.NET Core托管服务运行Quartz.NET作业.这样的好处是我们可以在应用程序启动和停止时很方便的来控制我们的Job的运行状态.接下来我将演示如何创建一个简 ...

  10. 使用Spring配置LogBack日志记录

    LogBack是由Log4j的同一作者创建的用于记录日志的API(较新的实现,它类似于新版本),在本文中,我将展示如何在Spring项目中对其进行集成和使用. 在本教程中,我假设您正在使用一个简单的S ...

最新文章

  1. 如何修改WINDOWS默认的3389远程端口
  2. ajax在Xss中的利用,XSS高级利用
  3. NTU 课程 7454 (5) CNN进阶
  4. 运算符重载 返回类型说明符后加_Java学习:运算符的使用与注意事项
  5. mysql trace工具_100% 展示 MySQL 语句执行的神器-Optimizer Trace
  6. ForkJoinPool 学习示例
  7. 产品狗,工作三年,转行AI应该怎样规划?
  8. 超漂亮的响应式个人主页
  9. win7分区软件_小编给你传授 win7系统给硬盘分区的修复方案 -win7系统使用教程...
  10. java能否回文_如何使用Java查找字符串是否是回文?
  11. CCNP 640-892知识点中文精简解释
  12. centos下安装VMware Server
  13. matlab与数学模型相结合例题,数学知识、数学建模、现代数学软件关系 与结合...
  14. voms下的反射大师_VOMS虚拟大师
  15. 如何寻找竞争情报发挥企业优势
  16. 测试人员的绩效考核,看看你有哪些没做好
  17. Autumn中文文档0:为什么使用Autumn
  18. 个人永久性免费-Excel催化剂功能第29波-追加中国特色的中文相关自定义函数
  19. 如何自学Java 经典
  20. Apache服务器配置参数的全面说明(所有参数)

热门文章

  1. 宝塔远程桌面助手使用教程
  2. 24速算c语言实训报告ppt,原创:C语言速算24数据结构课程设计最终版
  3. Android安全[app风险]
  4. (一)Activiti 数据库25张表——一般数据1 (ACT_GE_BYTEARRAY)
  5. 好玩的数据结构与算法——八皇后游戏(回溯)
  6. 通过比赛整理出的8条Numpy实用技巧【你知道如何频数统计和按某列进行排序么?】...
  7. Wox - 开源免费强大的快捷启动器辅助工具,快速高效率打开软件/搜索文件!
  8. 红色警戒最新版本哪个服务器好,红色警戒2里面哪个版本最好玩?
  9. idea2018下载-补丁破解激活
  10. Mac显示隐藏文件目录