-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathlog.go
146 lines (134 loc) · 3.33 KB
/
log.go
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package devstatscode
import (
"database/sql"
"fmt"
"os"
"strings"
"sync"
"time"
)
// Holds data needed to make DB calls
type logContext struct {
ctx Ctx
con *sql.DB
prog string
proj string
runDt time.Time
}
// This is the *only* global variable used in entire toolset.
// I want to save passing context and DB to all Printf(...) calls.
// This variable is initialized *only* once, and must be guared by the mutex
// to avoid initializing it from multiple go routines
var (
logCtx *logContext
logCtxMutex sync.RWMutex
logOnce sync.Once
logInitialized = false
logInitMtx sync.Mutex
BuildStamp = "None"
GitHash = "None"
HostName = "None"
GoVersion = "None"
)
// Returns new context when not yet created
func newLogContext() *logContext {
var ctx Ctx
ctx.Init()
ctx.PgDB = Devstats
con := PgConn(&ctx)
progSplit := strings.Split(os.Args[0], "/")
prog := progSplit[len(progSplit)-1]
now := time.Now()
if ctx.Debug >= 0 {
info := fmt.Sprintf("Compiled %s, commit: %s on %s using %s", BuildStamp, GitHash, HostName, GoVersion)
fmt.Printf("%s\n", info)
_, _ = ExecSQL(
con,
&ctx,
"insert into gha_logs(prog, proj, run_dt, msg) "+NValues(4),
prog,
ctx.Project,
now,
info,
)
}
defer func() {
logInitMtx.Lock()
logInitialized = true
logInitMtx.Unlock()
}()
return &logContext{
ctx: ctx,
con: con,
prog: prog,
proj: ctx.Project,
runDt: now,
}
}
// logToDB writes message to database
func logToDB(format string, args ...interface{}) (err error) {
logCtxMutex.RLock()
defer func() { logCtxMutex.RUnlock() }()
if logCtx.ctx.LogToDB == false {
return
}
msg := strings.Trim(fmt.Sprintf(format, args...), " \t\n\r")
_, err = ExecSQL(
logCtx.con,
&logCtx.ctx,
"insert into gha_logs(prog, proj, run_dt, msg) "+NValues(4),
logCtx.prog,
logCtx.proj,
logCtx.runDt,
msg,
)
return
}
// Printf is a wrapper around Printf(...) that supports logging.
func Printf(format string, args ...interface{}) (n int, err error) {
// Initialize context once
logOnce.Do(func() { logCtx = newLogContext() })
// Avoid query out on adding to logs itself
// it would print any text with its particular logs DB insert which
// would result in stdout mess
logCtxMutex.Lock()
qOut := logCtx.ctx.QOut
logCtx.ctx.QOut = false
logCtxMutex.Unlock()
defer func() {
logCtxMutex.Lock()
logCtx.ctx.QOut = qOut
logCtxMutex.Unlock()
}()
// Actual logging to stdout & DB
if logCtx.ctx.LogTime {
n, err = fmt.Printf("%s %s/%s: "+format, append([]interface{}{ToYMDHMSDate(time.Now()), logCtx.proj, logCtx.prog}, args...)...)
} else {
n, err = fmt.Printf(format, args...)
}
err = logToDB(format, args...)
return
}
// IsLogInitialized - check if log is initialized
func IsLogInitialized() bool {
logInitMtx.Lock()
defer logInitMtx.Unlock()
return logInitialized
}
// ClearDBLogs clears logs older by defined period (in context.go)
// It clears logs on `devstats` database
func ClearDBLogs() {
// Environment context parse
var ctx Ctx
ctx.Init()
// Point to logs database
ctx.PgDB = Devstats
// Connect to DB
c := PgConn(&ctx)
defer func() { _ = c.Close() }()
// Clear logs older that defined period
if !ctx.SkipPDB {
fmt.Printf("Clearing old DB logs.\n")
ExecSQLWithErr(c, &ctx, "delete from gha_logs where dt < now() - '"+ctx.ClearDBPeriod+"'::interval")
}
}