Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/reporting/exporters/jsonl/jsonl.go
2070 views
1
package jsonl
2
3
import (
4
"os"
5
"sync"
6
7
"github.com/pkg/errors"
8
"github.com/projectdiscovery/nuclei/v3/pkg/output"
9
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
10
)
11
12
type Exporter struct {
13
options *Options
14
mutex *sync.Mutex
15
rows []output.ResultEvent
16
outputFile *os.File
17
}
18
19
// Options contains the configuration options for JSONL exporter client
20
type Options struct {
21
// File is the file to export found JSONL result to
22
File string `yaml:"file"`
23
// OmitRaw whether to exclude the raw request and response from the output
24
OmitRaw bool `yaml:"omit-raw"`
25
// BatchSize the number of records to keep in memory before writing them out to the JSONL file or 0 to disable
26
// batching (default)
27
BatchSize int `yaml:"batch-size"`
28
}
29
30
// New creates a new JSONL exporter integration client based on options.
31
func New(options *Options) (*Exporter, error) {
32
exporter := &Exporter{
33
mutex: &sync.Mutex{},
34
options: options,
35
rows: []output.ResultEvent{},
36
}
37
return exporter, nil
38
}
39
40
// Export appends the passed result event to the list of objects to be exported to the resulting JSONL file
41
func (exporter *Exporter) Export(event *output.ResultEvent) error {
42
exporter.mutex.Lock()
43
defer exporter.mutex.Unlock()
44
45
if exporter.options.OmitRaw {
46
event.Request = ""
47
event.Response = ""
48
}
49
50
// Add the event to the rows
51
exporter.rows = append(exporter.rows, *event)
52
53
// If the batch size is greater than 0 and the number of rows has reached the batch, flush it to the database
54
if exporter.options.BatchSize > 0 && len(exporter.rows) >= exporter.options.BatchSize {
55
err := exporter.WriteRows()
56
if err != nil {
57
// The error is already logged, return it to bubble up to the caller
58
return err
59
}
60
}
61
62
return nil
63
}
64
65
// WriteRows writes all rows from the rows list to JSONL file and removes them from the list
66
func (exporter *Exporter) WriteRows() error {
67
// Open the file for writing if it's not already.
68
// This will recreate the file if it exists, but keep the file handle so that batched writes within the same
69
// execution are appended to the same file.
70
var err error
71
if exporter.outputFile == nil {
72
// Open the JSONL file for writing and create it if it doesn't exist
73
exporter.outputFile, err = os.OpenFile(exporter.options.File, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
74
if err != nil {
75
return errors.Wrap(err, "failed to create JSONL file")
76
}
77
}
78
79
// Loop through the rows and write them, removing them as they're entered
80
for len(exporter.rows) > 0 {
81
row := exporter.rows[0]
82
83
// Convert the row to JSON byte array and append a trailing newline. This is treated as a single line in JSONL
84
obj, err := json.Marshal(row)
85
if err != nil {
86
return errors.Wrap(err, "failed to generate row for JSONL report")
87
}
88
89
obj = append(obj, '\n')
90
91
// Attempt to append the JSON line to file specified in options.JSONLExport
92
if _, err = exporter.outputFile.Write(obj); err != nil {
93
return errors.Wrap(err, "failed to append JSONL line")
94
}
95
96
// Remove the item from the list
97
exporter.rows = exporter.rows[1:]
98
}
99
100
return nil
101
}
102
103
// Close writes the in-memory data to the JSONL file specified by options.JSONLExport and closes the exporter after
104
// operation
105
func (exporter *Exporter) Close() error {
106
exporter.mutex.Lock()
107
defer exporter.mutex.Unlock()
108
109
// Write any remaining rows to the file
110
// Write all pending rows
111
err := exporter.WriteRows()
112
if err != nil {
113
// The error is already logged, return it to bubble up to the caller
114
return err
115
}
116
117
// Close the file
118
if err := exporter.outputFile.Close(); err != nil {
119
return errors.Wrap(err, "failed to close JSONL file")
120
}
121
122
return nil
123
}
124
125