| 26 | ) |
| 27 | |
| 28 | func Scanner(ctx context.Context) error { |
| 29 | l := zerolog.Ctx(ctx) |
| 30 | |
| 31 | byteThroughputHist := prometheus.NewHistogramVec(prometheus.HistogramOpts{ |
| 32 | Name: "scanner_bytes_throughput_mib_per_second", |
| 33 | Help: "Speed of scan in Mib per second.", |
| 34 | Buckets: prometheus.ExponentialBuckets(1, 1.1, 100), |
| 35 | }, []string{"self", "op"}) |
| 36 | prometheus.DefaultRegisterer.MustRegister(byteThroughputHist) |
| 37 | |
| 38 | errChan := make(chan error, 1) |
| 39 | |
| 40 | go func() { |
| 41 | http.Handle("/metrics/prometheus", promhttp.Handler()) |
| 42 | if err := http.ListenAndServe("0.0.0.0:5004", nil); err != nil && !errors.Is(err, http.ErrServerClosed) { |
| 43 | errChan <- err |
| 44 | } |
| 45 | }() |
| 46 | |
| 47 | sleep(l) |
| 48 | |
| 49 | l.Info().Str("path", path).Msg("starting scanner") |
| 50 | |
| 51 | f, _ := os.OpenFile(path, os.O_RDONLY, 0644) |
| 52 | defer func() { |
| 53 | if err := f.Close(); err != nil { |
| 54 | l.Error().Err(err).Msg("failed to close file") |
| 55 | } |
| 56 | }() |
| 57 | |
| 58 | info, err := f.Stat() |
| 59 | if err != nil { |
| 60 | l.Fatal().Err(err).Msg("failed to stat file") |
| 61 | return err |
| 62 | } |
| 63 | |
| 64 | size := info.Size() |
| 65 | |
| 66 | bar := progressbar.DefaultBytes(size, "reading") |
| 67 | measure(bar, time.Now(), l, byteThroughputHist, float64(size)) |
| 68 | w, err := io.Copy(io.MultiWriter(io.Discard, bar), f) |
| 69 | if err != nil { |
| 70 | l.Fatal().Err(err).Msg("failed to read file") |
| 71 | return err |
| 72 | } else { |
| 73 | l.Info().Int64("size", size).Int64("read", w).Msg("complete") |
| 74 | } |
| 75 | |
| 76 | if err := <-errChan; err != nil { |
| 77 | l.Error().Msg(fmt.Sprintf("prom error: %v", err)) |
| 78 | } |
| 79 | |
| 80 | l.Info().Msg("sleeping to allow metrics scraping") |
| 81 | time.Sleep(24 * 365 * time.Hour) |
| 82 | |
| 83 | return err |
| 84 | } |
| 85 | |