如何过滤错误日志写入器:TLS握手错误

huangapple go评论90阅读模式
英文:

How to filter the error log writer: TLS handshake error

问题

如何在错误日志中过滤掉这些错误消息?这些消息会使错误日志泛滥,很难监控应用程序。

这些消息主要发生在某些东西尝试在没有任何HTTP请求的情况下建立TLS连接时。

2022/10/23 01:05:26 server.go:3230: http: TLS handshake error from xx.xx.xx.xx: read tcp xx.xx.xx.xx:x->xx.xx.xx.xx: read: connection reset by peer
2022/10/23 01:05:26 server.go:3230: http: TLS handshake error from xx.xx.xx.xx: tls: client requested unsupported application protocols ([http/0.9 http/1.0 spdy/1 spdy/2 spdy/3 h2c hq])
2022/10/23 02:58:54 server.go:3230: http: TLS handshake error from xx.xx.xx.xx: EOF
英文:

How to filter out these kind of error messages in the error log? These messages flood the error log and it's hard to monitor the application.

The messages mainly happens when something tries to make a TLS connection without any HTTP request

2022/10/23 01:05:26 server.go:3230: http: TLS handshake error from xx.xx.xx.xx: read tcp xx.xx.xx.xx:x->xx.xx.xx.xx: read: connection reset by peer
2022/10/23 01:05:26 server.go:3230: http: TLS handshake error from xx.xx.xx.xx: tls: client requested unsupported application protocols ([http/0.9 http/1.0 spdy/1 spdy/2 spdy/3 h2c hq])
2022/10/23 02:58:54 server.go:3230: http: TLS handshake error from xx.xx.xx.xx: EOF

答案1

得分: 0

http.Server有一个字段ErrorLog,你可以用自定义的写入器替换它的底层写入器,该写入器可以过滤掉包含"TLS handshake error"字符串的日志。

下面是一个简单的示例,其中包含两个服务器。一个服务器监听端口8443并使用完整的日志,另一个服务器使用过滤日志并监听端口8444。

客户端连接到这两个服务器。具有完整日志的服务器打印出http: TLS handshake error from 127.0.0.1:xxxxx: remote error: tls: bad certificate。而具有过滤日志的服务器不打印任何内容。

该示例演示了最简单的过滤日志器,它会过滤掉包含固定子字符串的行。

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"sync"
	"time"
)

// 过滤掉包含子字符串的行
type FilteringWriter struct {
	writer    io.Writer
	substring []byte
}

func (fw FilteringWriter) Write(b []byte) (n int, err error) {
	if bytes.Index(b, fw.substring) > -1 {
		// 过滤掉匹配模式的行
		return len(b), nil
	}
	return fw.writer.Write(b)
}

func NewFilteringWriter(writer io.Writer, pattern string) FilteringWriter {
	return FilteringWriter{
		writer:    writer,
		substring: []byte(pattern),
	}
}

// 服务器处理函数
func HelloWorld(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("Hello, world!\n"))
}

// 简单的服务器执行器
func runServer(server *http.Server, wg *sync.WaitGroup) {
	server.ListenAndServeTLS("server.crt", "server.key")
	wg.Done()
}

// 关闭服务器
func shutdownServer(server *http.Server) {
	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second))
	server.Shutdown(ctx)
	cancel()
}

func main() {
	fullLogger := log.New(
		os.Stderr,
		"full: ",
		log.LstdFlags,
	)
	// 过滤掉"TLS handshake error"的日志
	errorLogger := log.New(
		NewFilteringWriter(
			os.Stderr,
			"http: TLS handshake error",
		),
		"filtered: ",
		log.LstdFlags,
	)

	serverMux := http.NewServeMux()
	serverMux.HandleFunc("/hello", HelloWorld)

	server1 := &http.Server{
		Addr:     "localhost:8443",
		Handler:  serverMux,
		ErrorLog: fullLogger,
	}
	server2 := &http.Server{
		Addr:     "localhost:8444",
		Handler:  serverMux,
		ErrorLog: errorLogger,
	}

	wg := sync.WaitGroup{}
	wg.Add(2)
	go runServer(server1, &wg)
	go runServer(server2, &wg)

	// 测试日志记录器
	// 客户端连接到服务器
	// 具有完整日志的服务器打印
	// `http: TLS handshake error from 127.0.0.1:53182: remote error: tls: bad certificate`
	// 具有过滤日志的服务器不打印任何内容
	client := http.Client{}

	time.Sleep(100 * time.Millisecond)
	log.Println("客户端连接到具有完整日志的服务器")
	response, err := client.Get(fmt.Sprintf("https://%s/hello", server1.Addr))
	if err != nil {
		log.Printf("客户端失败:%v", err)
	} else {
		log.Printf("服务器返回:%v", response)
	}

	time.Sleep(100 * time.Millisecond)
	log.Println("客户端连接到具有过滤日志的服务器")
	response, err = client.Get(fmt.Sprintf("https://%s/hello", server2.Addr))
	if err != nil {
		log.Printf("客户端失败:%v", err)
	} else {
		log.Printf("服务器返回:%v", response)
	}

	shutdownServer(server1)
	shutdownServer(server2)
	wg.Wait()
}

输出:

2022/10/27 19:20:52 客户端连接到具有完整日志的服务器
2022/10/27 19:20:52 客户端失败:Get "https://localhost:8443/hello": x509: certificate is not valid for any names, but wanted to match localhost
full: 2022/10/27 19:20:52 http: TLS handshake error from 127.0.0.1:53182: remote error: tls: bad certificate
2022/10/27 19:20:52 客户端连接到具有过滤日志的服务器
2022/10/27 19:20:52 客户端失败:Get "https://localhost:8444/hello": x509: certificate is not valid for any names, but wanted to match localhost

如你所见,服务器1打印了日志行,而服务器2没有打印任何行。

英文:

http.Server has the field ErrorLog. You can replace its underlying writer with a custom writer that filters out strings containing "TLS handshake error"

Below is a simple example with two servers. One server listens to the port 8443 and uses the full log. The other server uses the filtering log and listens to the port 8444.

Client connects to the servers. The server with the full log prints http: TLS handshake error from 127.0.0.1:xxxxx: remote error: tls: bad certificate. The server with the filtering log pints nothing.

The example demonstrates the simplest filtering logger that filters away lines with a fixed substring.

package main
import (
"bytes"
"context"
"fmt"
"io"
"log"
"net/http"
"os"
"sync"
"time"
)
// Filters out lines that contain substring
type FilteringWriter struct {
writer    io.Writer
substring []byte
}
func (fw FilteringWriter) Write(b []byte) (n int, err error) {
if bytes.Index(b, fw.substring) > -1 {
// Filter out the line that matches the pattern
return len(b), nil
}
return fw.writer.Write(b)
}
func NewFilteringWriter(writer io.Writer, pattern string) FilteringWriter {
return FilteringWriter{
writer:    writer,
substring: []byte(pattern),
}
}
// Server handler function
func HelloWorld(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("Hello, world!\n"))
}
// Trivial server executor
func runServer(server *http.Server, wg *sync.WaitGroup) {
server.ListenAndServeTLS("server.crt", "server.key")
wg.Done()
}
// Shutdown server
func shutdownServer(server *http.Server) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second))
server.Shutdown(ctx)
cancel()
}
func main() {
fullLogger := log.New(
os.Stderr,
"full: ",
log.LstdFlags,
)
// Log that filters "TLS handshake error"
errorLogger := log.New(
NewFilteringWriter(
os.Stderr,
"http: TLS handshake error",
),
"filtered: ",
log.LstdFlags,
)
serverMux := http.NewServeMux()
serverMux.HandleFunc("/hello", HelloWorld)
server1 := &http.Server{
Addr:     "localhost:8443",
Handler:  serverMux,
ErrorLog: fullLogger,
}
server2 := &http.Server{
Addr:     "localhost:8444",
Handler:  serverMux,
ErrorLog: errorLogger,
}
wg := sync.WaitGroup{}
wg.Add(2)
go runServer(server1, &wg)
go runServer(server2, &wg)
// Test loggers
// Client connects to the servers
// The server with the full log prints
// `http: TLS handshake error from 127.0.0.1:53182: remote error: tls: bad certificate`
// the server with the filtering log pints nothing
client := http.Client{}
time.Sleep(100 * time.Millisecond)
log.Println("Client connects to the server with full log")
reponse, err := client.Get(fmt.Sprintf("https://%s/hello", server1.Addr))
if err != nil {
log.Printf("Client failed: %v", err)
} else {
log.Printf("Server returned: %v", reponse)
}
time.Sleep(100 * time.Millisecond)
log.Println("Client connects to the server with filtered log")
reponse, err = client.Get(fmt.Sprintf("https://%s/hello", server2.Addr))
if err != nil {
log.Printf("Client failed: %v", err)
} else {
log.Printf("Server returned: %v", reponse)
}
shutdownServer(server1)
shutdownServer(server2)
wg.Wait()
}

Ouput:

2022/10/27 19:20:52 Client connects to the server with full log
2022/10/27 19:20:52 Client failed: Get "https://localhost:8443/hello": x509: certificate is not valid for any names, but wanted to match localhost
full: 2022/10/27 19:20:52 http: TLS handshake error from 127.0.0.1:53182: remote error: tls: bad certificate
2022/10/27 19:20:52 Client connects to the server with filtered log
2022/10/27 19:20:52 Client failed: Get "https://localhost:8444/hello": x509: certificate is not valid for any names, but wanted to match localhost

As you see there is the log line from the server 1 and no lines for the server 2.

huangapple
  • 本文由 发表于 2022年10月23日 13:07:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/74168786.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定