summaryrefslogtreecommitdiff
path: root/datalogger/logger.go
blob: dd071a1df8f9d83be331be224cdfff4416c8db39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * This file is part of Go Responsiveness.
 *
 * Go Responsiveness is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 * Go Responsiveness is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with Go Responsiveness. If not, see <https://www.gnu.org/licenses/>.
 */

package datalogger

import (
	"fmt"
	"io"
	"os"
	"reflect"
	"sync"
)

type DataLogger[T any] interface {
	LogRecord(record T)
	Export() bool
	Close() bool
}

type CSVDataLogger[T any] struct {
	mut         *sync.Mutex
	recordCount int
	data        []T
	isOpen      bool
	destination io.WriteCloser
}

func CreateCSVDataLogger[T any](filename string) (DataLogger[T], error) {
	fmt.Printf("Creating a CSV data logger: %v!\n", filename)
	data := make([]T, 0)
	destination, err := os.Create(filename)
	if err != nil {
		return &CSVDataLogger[T]{&sync.Mutex{}, 0, data, true, destination}, err
	}

	result := CSVDataLogger[T]{&sync.Mutex{}, 0, data, true, destination}
	return &result, nil
}

func (logger *CSVDataLogger[T]) LogRecord(record T) {
	logger.mut.Lock()
	defer logger.mut.Unlock()
	logger.recordCount += 1
	logger.data = append(logger.data, record)
}

func (logger *CSVDataLogger[T]) Export() bool {
	logger.mut.Lock()
	defer logger.mut.Unlock()
	if !logger.isOpen {
		return false
	}

	t := new(T)
	visibleFields := reflect.VisibleFields(reflect.TypeOf(t).Elem())
	for _, v := range visibleFields {
		description, success := v.Tag.Lookup("Description")
		columnName := fmt.Sprintf("%s", v.Name)
		if success {
			columnName = fmt.Sprintf("%s", description)
		}
		logger.destination.Write([]byte(fmt.Sprintf("%s, ", columnName)))
	}
	logger.destination.Write([]byte("\n"))

	for _, d := range logger.data {
		for _, v := range visibleFields {
			data := reflect.ValueOf(d)
			toWrite := data.FieldByIndex(v.Index)
			logger.destination.Write([]byte(fmt.Sprintf("%v, ", toWrite)))
		}
		logger.destination.Write([]byte("\n"))
	}
	return true
}

func (logger *CSVDataLogger[T]) Close() bool {
	logger.mut.Lock()
	defer logger.mut.Unlock()
	if !logger.isOpen {
		return false
	}
	logger.destination.Close()
	logger.isOpen = false
	return true
}