func NewServer(
logger *Logger
config *Config
commentStore *commentStore
anotherStore *anotherStore
) http.Handler {
mux := http.NewServeMux()
addRoutes(
mux,
Logger,
Config,
commentStore,
anotherStore,
)
var handler http.Handler = mux
handler = someMiddleware(handler)
handler = someMiddleware2(handler)
handler = someMiddleware3(handler)
return handler
}
func addRoutes(
mux *http.ServeMux,
logger *logging.Logger,
config Config,
tenantsStore *TenantsStore,
commentsStore *CommentsStore,
conversationService *ConversationService,
chatGPTService *ChatGPTService,
authProxy *authProxy
) {
mux.Handle("/api/v1/", handleTenantsGet(logger, tenantsStore))
mux.Handle("/oauth2/", handleOAuth2Proxy(logger, authProxy))
mux.HandleFunc("/healthz", handleHealthzPlease(logger))
mux.Handle("/", http.NotFoundHandler())
}
func run(ctx context.Context, w io.Writer, args []string) error {
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
defer cancel()
// ...
}
func main() {
ctx := context.Background()
if err := run(ctx, os.Stdout, os.Args); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
}
// handleSomething handles one of those web requests
// that you hear so much about.
func handleSomething(logger *Logger) http.Handler {
thing := prepareThing()
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
// use thing to handle request
logger.Info(r.Context(), "msg", "handleSomething")
}
)
}
func encode[T any](w http.ResponseWriter, r *http.Request, status int, v T) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if err := json.NewEncoder(w).Encode(v); err != nil {
return fmt.Errorf("encode json: %w", err)
}
return nil
}
func decode[T any](r *http.Request) (T, error) {
var v T
if err := json.NewDecoder(r.Body).Decode(&v); err != nil {
return v, fmt.Errorf("decode json: %w", err)
}
return v, nil
}
// Validator is an object that can be validated.
type Validator interface {
// Valid checks the object and returns any
// problems. If len(problems) == 0 then
// the object is valid.
Valid(ctx context.Context) (problems map[string]string)
}
func decodeValid[T Validator](r *http.Request) (T, map[string]string, error) {
var v T
if err := json.NewDecoder(r.Body).Decode(&v); err != nil {
return v, nil, fmt.Errorf("decode json: %w", err)
}
if problems := v.Valid(r.Context()); len(problems) > 0 {
return v, problems, fmt.Errorf("invalid %T: %d problems", v, len(problems))
}
return v, nil, nil
}
自定义校验需要实现 Validator 接口。
func handleTemplate(files string...) http.HandlerFunc {
var (
init sync.Once
tpl *template.Template
tplerr error
)
return func(w http.ResponseWriter, r *http.Request) {
init.Do(func(){
tpl, tplerr = template.ParseFiles(files...)
})
if tplerr != nil {
http.Error(w, tplerr.Error(), http.StatusInternalServerError)
return
}
// use tpl
}
}
What is OpenTelemetry?
这是一篇 OTel 的科普文章
OpenTelemetry 提供一个统一、可扩展的框架,用于收集、分析和观察分布式系统的性能数据。它包括一组API、库、代理和收集器,这些组件可以跨多种编程语言和平台实现对应用程序的监控。
OpenTelemetry 整合 OpenTracing 和 OpenCensus。
2019年,两个社区进行了合并。
同时 OTel 具备以下特征:
提供了一种名为:OTLP(OpenTelemetry Protocol)的通讯协议,基于 gRPC。
使用该协议用于客户端与 Collector 采集器进行交互。
Collector 是 OpenTelemetry 架构中的一个关键组件,它负责接收、处理和导出数据(Trace/log/metrics)。
它可以接受从客户端发出的数据进行处理,同时可以导出为不同格式的数据。
总的来说 OTel 是可观测系统的新标准,基于它可以兼容以前使用的 Prometheus、 victoriametrics、skywalking 等系统,同时还可以灵活扩展,不用与任何但一生态或技术栈进行绑定。
Popular git config options
本文总结了一些常用的 git 配置
文章链接:
- https://grafana.com/blog/2024/02/09/how-i-write-http-services-in-go-after-13-years/
- https://codeboten.medium.com/what-is-opentelemetry-6a7e5c6901c5
- https://jvns.ca/blog/2024/02/16/popular-git-config-options/