New creates a new middleware handler
(config ...Config)
| 28 | |
| 29 | // New creates a new middleware handler |
| 30 | func New(config ...Config) fiber.Handler { |
| 31 | // Set default config |
| 32 | cfg := configDefault(config...) |
| 33 | |
| 34 | // Get timezone location |
| 35 | tz, err := time.LoadLocation(cfg.TimeZone) |
| 36 | if err != nil { |
| 37 | cfg.timeZoneLocation = time.Local |
| 38 | } else { |
| 39 | cfg.timeZoneLocation = tz |
| 40 | } |
| 41 | |
| 42 | // Check if format contains latency |
| 43 | cfg.isLatencyEnabled = strings.Contains(cfg.Format, "${"+TagLatency+"}") |
| 44 | |
| 45 | timeEnabled := strings.Contains(cfg.Format, "${"+TagTime+"}") |
| 46 | var timestamp *atomic.Value |
| 47 | if timeEnabled { |
| 48 | if cfg.TimeDone != nil { |
| 49 | // Caller-managed lifecycle: dedicated updater so it can be stopped |
| 50 | // via TimeDone (useful for tests and short-lived apps). |
| 51 | timestamp = &atomic.Value{} |
| 52 | timestamp.Store(time.Now().In(cfg.timeZoneLocation).Format(cfg.TimeFormat)) |
| 53 | startTimestampUpdater(timestamp, &cfg) |
| 54 | } else { |
| 55 | // Process-lifetime shared updater, deduplicated by format/zone/interval. |
| 56 | timestamp = sharedTimestamp(cfg.TimeFormat, cfg.timeZoneLocation, cfg.TimeInterval) |
| 57 | } |
| 58 | } |
| 59 | // Set PID once |
| 60 | pid := strconv.Itoa(os.Getpid()) |
| 61 | |
| 62 | // Set variables |
| 63 | var ( |
| 64 | once sync.Once |
| 65 | errHandler fiber.ErrorHandler |
| 66 | |
| 67 | dataPool = sync.Pool{New: func() any { return new(Data) }} |
| 68 | ) |
| 69 | |
| 70 | // Err padding starts at the documented default and grows once on first |
| 71 | // request to fit the longest registered route path. |
| 72 | errPadding := defaultErrPadding |
| 73 | errPaddingStr := strconv.Itoa(errPadding) |
| 74 | |
| 75 | // Before handling func |
| 76 | cfg.BeforeHandlerFunc(&cfg) |
| 77 | |
| 78 | // Logger data |
| 79 | // instead of analyzing the template inside(handler) each time, this is done once before |
| 80 | // and we create several slices of the same length with the functions to be executed and fixed parts. |
| 81 | template, err := logtemplate.Build[fiber.Ctx, Data](cfg.Format, createTagMap(&cfg)) |
| 82 | if err != nil { |
| 83 | if translated := translateBuildError(err); translated != nil { |
| 84 | panic(translated) |
| 85 | } |
| 86 | panic(err) |
| 87 | } |