我编写了一个用于将 Azure 应用程序见解与 Zerolog 集成的代码,我不确定的一件事是如何获取挂钩函数内的事件字段,以便我可以将数据字段发布到 Azure 应用程序见解自定义属性字段中或者在那里任何其他更清洁的方法来实现这一目标。
有人认为 Zerolog 应该公开一个函数来获取字段吗?
package zeroappinsights
import (
"context"
"encoding/json"
"github.com/gin-gonic/gin"
"net/http"
"os"
"time"
"github.com/microsoft/ApplicationInsights-Go/appinsights"
"github.com/microsoft/ApplicationInsights-Go/appinsights/contracts"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/org/package/constants"
"github.com/org/package/models"
)
var levelMap = map[zerolog.Level]contracts.SeverityLevel{
zerolog.ErrorLevel: contracts.Error,
zerolog.InfoLevel: contracts.Information,
zerolog.DebugLevel: contracts.Verbose,
zerolog.FatalLevel: contracts.Critical,
zerolog.WarnLevel: contracts.Warning,
}
var appInsightsProperties = []string{
contracts.OperationId,
contracts.OperationParentId,
contracts.UserId,
contracts.SessionId,
}
type TracingHook struct {
env constants.Environment
telemetryClient appinsights.TelemetryClient
file *os.File
eventsMap map[string]string
}
func NewAITracing(serviceName, instrumentationKey string, env constants.Environment, eventsMap map[string]string) *TracingHook {
client := appinsights.NewTelemetryClient(instrumentationKey)
client.Context().Tags.Cloud().SetRole(serviceName)
if env.IsLocal() {
file, err := os.OpenFile(serviceName+".log", os.O_CREATE, 0644)
if err != nil {
return nil
}
return &TracingHook{
telemetryClient: client,
file: file,
env: constants.Local,
}
}
return &TracingHook{
telemetryClient: client,
file: nil,
env: env,
eventsMap: eventsMap,
}
}
func (h *TracingHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
ctx := e.GetCtx()
if appinsightsLevel, ok := levelMap[level]; ok {
trace := appinsights.NewTraceTelemetry(msg, appinsightsLevel)
for _, property := range appInsightsProperties {
trace.Tags[property] = ctx.Value(property).(string)
}
//I want to add more properties from the event to trace.Properties
trace.Timestamp = time.Now().UTC()
if h.env.IsLocal() {
// Marshal the request into a JSON byte slice
traceJSON, err := json.Marshal(trace)
if err != nil {
log.Printf("error marshaling request: %v", err)
return
}
if _, err = h.file.Write(append(traceJSON, '\n')); err != nil {
log.Printf("error occurred while writing to file: %v", err)
return
}
} else {
go h.telemetryClient.Track(trace)
}
}
}
func (h *TracingHook) LoggingMiddleware(logger zerolog.Logger) func(c *gin.Context) {
return func(c *gin.Context) {
startTime := time.Now().UTC()
telemetry := appinsights.NewEventTelemetry(h.eventsMap[c.Request.URL.Path])
h.telemetryClient.Track(telemetry)
operationID := telemetry.Tags[contracts.OperationId]
operationParentID := telemetry.Tags[contracts.OperationParentId]
userID := telemetry.Tags[contracts.UserId]
sessionID := telemetry.Tags[contracts.SessionId]
if value, exists := c.Get("userProfile"); exists {
profile := value.(models.UserProfile)
userID = profile.ID
sessionID = c.Request.Header.Get(constants.Session)
}
values := []string{operationID, operationParentID, userID, sessionID}
ctx := c.Request.Context()
for i, key := range appInsightsProperties {
ctx = context.WithValue(ctx, key, values[i])
}
loggerContext := logger.WithContext(ctx)
c.Set("loggerCtx", loggerContext)
c.Next()
duration := time.Since(startTime)
request := appinsights.NewRequestTelemetry(c.Request.Method, c.Request.URL.Path, duration, http.StatusText(c.Writer.Status()))
request.Timestamp = time.Now().UTC()
tags := request.Tags
tags[contracts.OperationId] = operationID
tags[contracts.OperationParentId] = operationParentID
tags[contracts.UserId] = userID
tags[contracts.SessionId] = sessionID
request.Tags = tags
if h.env.IsLocal() {
// Marshal the request into a JSON byte slice
requestJSON, err := json.Marshal(request)
if err != nil {
log.Printf("error marshaling request: %v", err)
return
}
if _, err = h.file.Write(append(requestJSON, '\n')); err != nil {
log.Printf("error occurred while writing to file: %v", err)
return
}
return
}
h.telemetryClient.Track(request)
}
}
下面您可以看到挂钩函数,该函数从
Zerolog
事件中提取相关信息并将其添加到 Application Insights 遥测属性中。
代码:
package zeroappinsights
import (
"context"
"encoding/json"
"net/http"
"os"
"time"
"github.com/gin-gonic/gin"
"github.com/microsoft/ApplicationInsights-Go/appinsights"
"github.com/microsoft/ApplicationInsights-Go/appinsights/contracts"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/org/package/constants"
"github.com/org/package/models"
)
var levelMap = map[zerolog.Level]contracts.SeverityLevel{
zerolog.ErrorLevel: contracts.Error,
zerolog.InfoLevel: contracts.Information,
zerolog.DebugLevel: contracts.Verbose,
zerolog.FatalLevel: contracts.Critical,
zerolog.WarnLevel: contracts.Warning,
}
var appInsightsProperties = []string{
contracts.OperationId,
contracts.OperationParentId,
contracts.UserId,
contracts.SessionId,
}
// ApplicationInsightsHook is a Zerolog hook that sends log entries to Application Insights
type ApplicationInsightsHook struct {
client appinsights.TelemetryClient
}
// NewApplicationInsightsHook creates a new ApplicationInsightsHook
func NewApplicationInsightsHook(instrumentationKey string) *ApplicationInsightsHook {
client := appinsights.NewTelemetryClient(instrumentationKey)
return &ApplicationInsightsHook{client: client}
}
// Fire is called when a log event is fired.
func (hook *ApplicationInsightsHook) Fire(e *zerolog.Event) error {
severity, ok := levelMap[e.Level()]
if !ok {
severity = contracts.Verbose
}
telemetry := appinsights.NewTraceTelemetry(e.Message().String(), severity)
// Add custom properties
e.Fields(func(key string, value interface{}) {
telemetry.Properties[key] = fmt.Sprintf("%v", value)
})
// Add predefined properties
for _, prop := range appInsightsProperties {
if value, ok := e.Context[prop].(string); ok {
telemetry.Properties[prop] = value
}
}
hook.client.Track(telemetry)
return nil
}
// Levels returns the log levels to enable for this hook.
func (hook *ApplicationInsightsHook) Levels() []zerolog.Level {
return []zerolog.Level{
zerolog.PanicLevel,
zerolog.FatalLevel,
zerolog.ErrorLevel,
zerolog.WarnLevel,
zerolog.InfoLevel,
zerolog.DebugLevel,
}
}
// SetLogger sets the logger for the hook.
func (hook *ApplicationInsightsHook) SetLogger(logger *zerolog.Logger) {
*logger = logger.Hook(hook)
}
// Usage:
func main() {
// Initialize the Application Insights hook
aiHook := NewApplicationInsightsHook("your-instrumentation-key")
// Create a Zerolog logger and set the hook
logger := zerolog.New(os.Stdout).With().Timestamp().Logger()
aiHook.SetLogger(&logger)
// Use the logger as usual
logger.Info().Str("customField", "customValue").Msg("Log message")
}
通过这个
ApplicationInsightsHook
结构体被创建并实现 zerolog.Hook
接口。
当日志事件触发时,会调用
Fire
方法,它从 Zerolog 事件中提取相关信息(包括自定义字段),并将它们添加到 Application Insights 遥测中。