feat(csv): change to csv from jsonl
This commit is contained in:
@@ -75,7 +75,7 @@ func (r *MeasurementRunner) runMeasurement(upstream string, domains []string, qT
|
|||||||
defer dnsClient.Close()
|
defer dnsClient.Close()
|
||||||
|
|
||||||
// Setup output files
|
// Setup output files
|
||||||
jsonPath, pcapPath := GenerateOutputPaths(r.config.OutputDir, upstream, r.config.DNSSEC, r.config.KeepAlive)
|
csvPath, pcapPath := GenerateOutputPaths(r.config.OutputDir, upstream, r.config.DNSSEC, r.config.KeepAlive)
|
||||||
|
|
||||||
keepAliveStr := ""
|
keepAliveStr := ""
|
||||||
if r.config.KeepAlive {
|
if r.config.KeepAlive {
|
||||||
@@ -83,7 +83,7 @@ func (r *MeasurementRunner) runMeasurement(upstream string, domains []string, qT
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(">>> Measuring %s (dnssec=%v%s) → %s\n", upstream, r.config.DNSSEC, keepAliveStr,
|
fmt.Printf(">>> Measuring %s (dnssec=%v%s) → %s\n", upstream, r.config.DNSSEC, keepAliveStr,
|
||||||
strings.TrimSuffix(strings.TrimSuffix(jsonPath, ".jsonl"), r.config.OutputDir+"/"))
|
strings.TrimSuffix(strings.TrimSuffix(csvPath, ".csv"), r.config.OutputDir+"/"))
|
||||||
|
|
||||||
// Setup packet capture
|
// Setup packet capture
|
||||||
packetCapture, err := capture.NewPacketCapture(r.config.Interface, pcapPath)
|
packetCapture, err := capture.NewPacketCapture(r.config.Interface, pcapPath)
|
||||||
@@ -93,7 +93,7 @@ func (r *MeasurementRunner) runMeasurement(upstream string, domains []string, qT
|
|||||||
defer packetCapture.Close()
|
defer packetCapture.Close()
|
||||||
|
|
||||||
// Setup results writer
|
// Setup results writer
|
||||||
writer, err := results.NewMetricsWriter(jsonPath)
|
writer, err := results.NewMetricsWriter(csvPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package results
|
package results
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/csv"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,29 +24,69 @@ type DNSMetric struct {
|
|||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rest stays exactly the same
|
|
||||||
type MetricsWriter struct {
|
type MetricsWriter struct {
|
||||||
encoder *json.Encoder
|
writer *csv.Writer
|
||||||
file *os.File
|
file *os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMetricsWriter(path string) (*MetricsWriter, error) {
|
func NewMetricsWriter(path string) (*MetricsWriter, error) {
|
||||||
file, err := os.Create(path)
|
file, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create json output: %w", err)
|
return nil, fmt.Errorf("create csv output: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer := csv.NewWriter(file)
|
||||||
|
|
||||||
|
// Write CSV header
|
||||||
|
header := []string{
|
||||||
|
"domain", "query_type", "protocol", "dnssec", "keep_alive",
|
||||||
|
"dns_server", "timestamp", "duration_ns", "duration_ms",
|
||||||
|
"request_size_bytes", "response_size_bytes", "response_code", "error",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writer.Write(header); err != nil {
|
||||||
|
file.Close()
|
||||||
|
return nil, fmt.Errorf("write csv header: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Flush()
|
||||||
|
|
||||||
return &MetricsWriter{
|
return &MetricsWriter{
|
||||||
encoder: json.NewEncoder(file),
|
writer: writer,
|
||||||
file: file,
|
file: file,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mw *MetricsWriter) WriteMetric(metric DNSMetric) error {
|
func (mw *MetricsWriter) WriteMetric(metric DNSMetric) error {
|
||||||
return mw.encoder.Encode(metric)
|
record := []string{
|
||||||
|
metric.Domain,
|
||||||
|
metric.QueryType,
|
||||||
|
metric.Protocol,
|
||||||
|
strconv.FormatBool(metric.DNSSEC),
|
||||||
|
strconv.FormatBool(metric.KeepAlive),
|
||||||
|
metric.DNSServer,
|
||||||
|
metric.Timestamp.Format(time.RFC3339),
|
||||||
|
strconv.FormatInt(metric.Duration, 10),
|
||||||
|
strconv.FormatFloat(metric.DurationMs, 'f', 3, 64),
|
||||||
|
strconv.Itoa(metric.RequestSize),
|
||||||
|
strconv.Itoa(metric.ResponseSize),
|
||||||
|
metric.ResponseCode,
|
||||||
|
metric.Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mw.writer.Write(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mw.writer.Flush()
|
||||||
|
return mw.writer.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mw *MetricsWriter) Close() error {
|
func (mw *MetricsWriter) Close() error {
|
||||||
|
if mw.writer != nil {
|
||||||
|
mw.writer.Flush()
|
||||||
|
}
|
||||||
if mw.file != nil {
|
if mw.file != nil {
|
||||||
return mw.file.Close()
|
return mw.file.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateOutputPaths(outputDir, upstream string, dnssec, keepAlive bool) (jsonPath, pcapPath string) {
|
func GenerateOutputPaths(outputDir, upstream string, dnssec, keepAlive bool) (csvPath, pcapPath string) {
|
||||||
proto := DetectProtocol(upstream)
|
proto := DetectProtocol(upstream)
|
||||||
serverName := ExtractServerName(upstream)
|
serverName := ExtractServerName(upstream)
|
||||||
ts := time.Now().Format("20060102_1504")
|
ts := time.Now().Format("20060102_1504")
|
||||||
@@ -18,8 +18,8 @@ func GenerateOutputPaths(outputDir, upstream string, dnssec, keepAlive bool) (js
|
|||||||
base := fmt.Sprintf("%s_%s_dnssec_%s_keepalive_%s_%s",
|
base := fmt.Sprintf("%s_%s_dnssec_%s_keepalive_%s_%s",
|
||||||
proto, sanitize(serverName), dnssecStr, keepAliveStr, ts)
|
proto, sanitize(serverName), dnssecStr, keepAliveStr, ts)
|
||||||
|
|
||||||
return filepath.Join(outputDir, base+".jsonl"),
|
return filepath.Join(outputDir, base+".csv"),
|
||||||
filepath.Join(outputDir, base+".pcap")
|
filepath.Join(outputDir, base+".pcap")
|
||||||
}
|
}
|
||||||
|
|
||||||
func sanitize(s string) string {
|
func sanitize(s string) string {
|
||||||
|
|||||||
Reference in New Issue
Block a user