nuclei/pkg/scan/events/stats_build.go
Dwi Siswanto 622c5503fa
perf(*): replace encoding/json w/ sonic or go-json (fallback) (#6019)
* perf(*): replace `encoding/json` w/ sonic

Signed-off-by: Dwi Siswanto <git@dw1.io>

* feat(utils): add `json` pkg (sonic wrapper)

Signed-off-by: Dwi Siswanto <git@dw1.io>

* chore(*): use `sonic` wrapper instead

Signed-off-by: Dwi Siswanto <git@dw1.io>

* chore(*): replace `sonic.ConfigStd` -> `json` (wrapper)

Signed-off-by: Dwi Siswanto <git@dw1.io>

* test(model): adjust expected marshal'd JSON

Signed-off-by: Dwi Siswanto <git@dw1.io>

* feat(json): dynamic backend; `sonic` -> `go-json` (fallback)

Signed-off-by: Dwi Siswanto <git@dw1.io>

* chore(json): merge config - as its not usable

Signed-off-by: Dwi Siswanto <git@dw1.io>

* chore(json): rm go version constraints

Signed-off-by: Dwi Siswanto <git@dw1.io>

* chore: go mod tidy

Signed-off-by: Dwi Siswanto <git@dw1.io>

---------

Signed-off-by: Dwi Siswanto <git@dw1.io>
2025-02-11 03:01:37 +05:30

103 lines
2.1 KiB
Go

//go:build stats
// +build stats
package events
import (
"fmt"
"os"
"path/filepath"
"sync"
"time"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
)
var _ ScanEventWorker = &ScanStatsWorker{}
var defaultWorker = &ScanStatsWorker{}
// ScanStatsWorker is a worker for scanning stats
// This tracks basic stats in jsonlines format
// in given directory or a default directory with name stats_{timestamp} in the current directory
type ScanStatsWorker struct {
config *ScanConfig
m *sync.Mutex
directory string
file *os.File
enc *json.Encoder
}
// Init initializes the scan stats worker
func InitWithConfig(config *ScanConfig, statsDirectory string) {
currentTime := time.Now().Format("20060102150405")
dirName := fmt.Sprintf("nuclei-stats-%s", currentTime)
err := os.Mkdir(dirName, 0755)
if err != nil {
panic(err)
}
// save the config to the directory
bin, err := json.MarshalIndent(config, "", " ")
if err != nil {
panic(err)
}
err = os.WriteFile(filepath.Join(dirName, ConfigFile), bin, 0755)
if err != nil {
panic(err)
}
defaultWorker = &ScanStatsWorker{config: config, m: &sync.Mutex{}, directory: dirName}
err = defaultWorker.initEventsFile()
if err != nil {
panic(err)
}
}
// initEventsFile initializes the events file for the worker
func (s *ScanStatsWorker) initEventsFile() error {
f, err := os.Create(filepath.Join(s.directory, EventsFile))
if err != nil {
return err
}
s.file = f
s.enc = json.NewEncoder(f)
return nil
}
// AddScanEvent adds a scan event to the worker
func (s *ScanStatsWorker) AddScanEvent(event ScanEvent) {
s.m.Lock()
defer s.m.Unlock()
err := s.enc.Encode(event)
if err != nil {
panic(err)
}
}
// AddScanEvent adds a scan event to the worker
func AddScanEvent(event ScanEvent) {
if defaultWorker == nil {
return
}
defaultWorker.AddScanEvent(event)
}
// Close closes the file associated with the worker
func (s *ScanStatsWorker) Close() {
s.m.Lock()
defer s.m.Unlock()
if s.file != nil {
_ = s.file.Close()
s.file = nil
}
}
// Close closes the file associated with the worker
func Close() {
if defaultWorker == nil {
return
}
defaultWorker.Close()
}