You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
3.6 KiB
173 lines
3.6 KiB
6 years ago
|
package utility
|
||
|
|
||
|
import (
|
||
|
"database/sql"
|
||
|
"io"
|
||
|
"os"
|
||
|
"time"
|
||
|
|
||
|
"strings"
|
||
|
|
||
|
"github.com/ipsusila/opt"
|
||
|
)
|
||
|
|
||
|
//SQLWriter write log to database i.e. SQLite
|
||
|
type SQLWriter struct {
|
||
|
db *sql.DB
|
||
|
insertQuery string
|
||
|
createQuery string
|
||
|
appID string
|
||
|
}
|
||
|
|
||
|
//LogWriter support multiple output
|
||
|
type LogWriter struct {
|
||
|
writers []io.WriteCloser
|
||
|
console bool
|
||
|
}
|
||
|
|
||
|
//NewLogWriter create multiple writer
|
||
|
func NewLogWriter(options *opt.Options) (*LogWriter, error) {
|
||
|
logOpt := options.Get("log")
|
||
|
|
||
|
//backward compatibility, get from server
|
||
|
appID := options.Get("server").GetString("id", "")
|
||
|
if appID == "" {
|
||
|
//if failed, get from `log.id`
|
||
|
appID = logOpt.GetString("id", "")
|
||
|
}
|
||
|
if appID == "" {
|
||
|
//if failed, get from `id``
|
||
|
appID = options.GetString("id", "*undefined*")
|
||
|
}
|
||
|
|
||
|
outTypes := logOpt.GetString("type", "")
|
||
|
typeItems := strings.Split(outTypes, ",")
|
||
|
writers := []io.WriteCloser{}
|
||
|
|
||
|
console := false
|
||
|
for _, item := range typeItems {
|
||
|
item = strings.TrimSpace(item)
|
||
|
switch item {
|
||
|
case "console":
|
||
|
console = true
|
||
|
case "file":
|
||
|
fileOpt := logOpt.Get("file")
|
||
|
name := fileOpt.GetString("name", "")
|
||
|
appendExisting := fileOpt.GetBool("append", true)
|
||
|
flag := os.O_WRONLY | os.O_CREATE
|
||
|
if appendExisting {
|
||
|
flag |= os.O_APPEND
|
||
|
} else {
|
||
|
flag |= os.O_TRUNC
|
||
|
}
|
||
|
|
||
|
f, err := os.OpenFile(name, flag, 0666)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
writers = append(writers, f)
|
||
|
case "sql":
|
||
|
w, err := newSQLWriter(logOpt, appID)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
writers = append(writers, w)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lw := &LogWriter{
|
||
|
writers: writers,
|
||
|
console: console,
|
||
|
}
|
||
|
|
||
|
return lw, nil
|
||
|
}
|
||
|
|
||
|
//NewSQLWriter open log writer to sql
|
||
|
func newSQLWriter(logOpt *opt.Options, appID string) (*SQLWriter, error) {
|
||
|
sqlOpt := logOpt.Get("sql")
|
||
|
dbDriver := sqlOpt.GetString("driver", "")
|
||
|
dbInfo := sqlOpt.GetString("connection", "")
|
||
|
createQuery := sqlOpt.GetString("createQuery", "")
|
||
|
insertQuery := sqlOpt.GetString("insertQuery", "")
|
||
|
dbMaxIdle := sqlOpt.GetInt("maxIdle", 0)
|
||
|
dbMaxOpen := sqlOpt.GetInt("maxOpen", 5)
|
||
|
dbMaxLifetime := time.Duration(sqlOpt.GetInt("maxLifetime", 60)) * time.Second
|
||
|
|
||
|
//open databae connection
|
||
|
db, err := sql.Open(dbDriver, dbInfo)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
err = db.Ping()
|
||
|
if err != nil {
|
||
|
db.Close()
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
//connection pooling
|
||
|
db.SetMaxIdleConns(dbMaxIdle)
|
||
|
db.SetMaxOpenConns(dbMaxOpen)
|
||
|
db.SetConnMaxLifetime(dbMaxLifetime)
|
||
|
|
||
|
//ignore error
|
||
|
//TODO, verify query (security, untrusted source)
|
||
|
db.Exec(createQuery)
|
||
|
|
||
|
w := &SQLWriter{
|
||
|
db: db,
|
||
|
createQuery: createQuery,
|
||
|
insertQuery: insertQuery,
|
||
|
appID: appID,
|
||
|
}
|
||
|
|
||
|
return w, nil
|
||
|
}
|
||
|
|
||
|
//Write to multiple log
|
||
|
func (lw *LogWriter) Write(data []byte) (n int, err error) {
|
||
|
//now := time.Now().Format("[2006-01-02 15:04:05]")
|
||
|
if lw.console {
|
||
|
n, err = os.Stderr.Write(data)
|
||
|
}
|
||
|
for _, w := range lw.writers {
|
||
|
n, err = w.Write(data)
|
||
|
}
|
||
|
|
||
|
return n, err
|
||
|
}
|
||
|
|
||
|
//Close all writer
|
||
|
func (lw *LogWriter) Close() error {
|
||
|
for _, w := range lw.writers {
|
||
|
w.Close()
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
//Write data with timestamp (ts, log)
|
||
|
func (w *SQLWriter) Write(data []byte) (int, error) {
|
||
|
//TODO, verify query (security, untrusted source)
|
||
|
result, err := w.db.Exec(w.insertQuery, time.Now(), w.appID, string(data))
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
|
||
|
n := len(data)
|
||
|
_, err = result.LastInsertId()
|
||
|
if err != nil {
|
||
|
return n, err
|
||
|
}
|
||
|
|
||
|
nrows, err := result.RowsAffected()
|
||
|
if err != nil || nrows == 0 {
|
||
|
return n, err
|
||
|
}
|
||
|
|
||
|
return n, nil
|
||
|
}
|
||
|
|
||
|
func (w *SQLWriter) Close() error {
|
||
|
return w.db.Close()
|
||
|
}
|