diff --git a/Makefile b/Makefile index 330dc96..054ab4f 100644 --- a/Makefile +++ b/Makefile @@ -5,4 +5,4 @@ run: APP_LOG_PRETTY=true \ APP_DB_TYPE=sqlite \ APP_DATA=work \ - go run main.go \ No newline at end of file + go run cmd/test/main.go \ No newline at end of file diff --git a/README.md b/README.md index b126c23..dd63f95 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ # Kumoly App -combine all needed module into one lib \ No newline at end of file +combine all needed module into one lib + +## Run + +``` + +``` \ No newline at end of file diff --git a/scripts/build.sh b/build.sh similarity index 100% rename from scripts/build.sh rename to build.sh diff --git a/main.go b/cmd/test/main.go similarity index 76% rename from main.go rename to cmd/test/main.go index 674cc2f..758eed3 100644 --- a/main.go +++ b/cmd/test/main.go @@ -2,6 +2,7 @@ package main import ( "kumoly.io/kumoly/app/auth" + "kumoly.io/kumoly/app/history" "kumoly.io/kumoly/app/server" "kumoly.io/kumoly/app/store" "kumoly.io/kumoly/app/system" @@ -17,7 +18,7 @@ func main() { auth.SetDB(store.DB) sys.Inject(auth.Injector(server.API)) - sys.Append(server, auth.New(server), &task.Service{}) + sys.Append(server, auth.New(server), &task.Service{}, &history.Service{}) sys.Start() } diff --git a/history/helper.go b/history/helper.go new file mode 100644 index 0000000..f1bf463 --- /dev/null +++ b/history/helper.go @@ -0,0 +1,27 @@ +package history + +import "kumoly.io/kumoly/app/util" + +func Error() *History { + h := getBase() + h.Type = ERROR + if !PROD { + h.Trace = util.Stack() + } + return h +} + +func Info() *History { + h := getBase() + h.Type = INFO + return h +} + +func getBase() *History { + mod, file := util.CallerMod(3) + h := &History{ + Module: mod, + Caller: file, + } + return h +} diff --git a/history/history.go b/history/history.go new file mode 100644 index 0000000..0e06433 --- /dev/null +++ b/history/history.go @@ -0,0 +1,102 @@ +package history + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/rs/zerolog/log" + "gorm.io/gorm" + "kumoly.io/kumoly/app/errors" + "kumoly.io/kumoly/app/store" +) + +var PROD = false + +const ( + ERROR = "ERROR" + INFO = "INFO" +) + +type History struct { + ID uint `gorm:"primaryKey"` + CreatedAt time.Time + + Module string + Type string + + Message string + BodyJson string + Body interface{} `gorm:"-"` + Issuer string + Caller string + Trace string +} + +func (h *History) BeforeCreate(tx *gorm.DB) (err error) { + if h.Body != nil { + body, err := json.Marshal(h.Body) + if err != nil { + h.BodyJson = string(body) + } + } + return +} + +var Tunnel chan *History +var quit chan struct{} +var started chan struct{} + +func init() { + Tunnel = make(chan *History) + quit = make(chan struct{}, 1) + started = make(chan struct{}, 1) +} + +func Start(r Receiver) { + select { + case started <- struct{}{}: + default: + panic(errors.New(500, "history reporter has already started!")) + } + go func() { + for { + select { + case h := <-Tunnel: + if Interceptor != nil { + go Interceptor(h) + } + r(h) + case <-quit: + <-started + return + } + } + }() +} + +func Stop() { + quit <- struct{}{} +} + +func Send(h *History) { + if h.Type == "" { + h.Type = INFO + } + Tunnel <- h +} + +type Receiver func(*History) + +var Interceptor func(*History) = nil + +var DBReceiver Receiver = func(h *History) { + err := store.DB.Create(h).Error + if err != nil { + log.Error().Str("mod", "history").Err(err).Msg("DBReceiver error") + } +} + +var ConsoleReceiver Receiver = func(h *History) { + fmt.Printf("%+v\n", h) +} diff --git a/history/history_test.go b/history/history_test.go new file mode 100644 index 0000000..b9852fa --- /dev/null +++ b/history/history_test.go @@ -0,0 +1,32 @@ +package history + +import ( + "testing" + "time" + + "kumoly.io/kumoly/app/util" +) + +func TestHistory(t *testing.T) { + t.Log("start") + Start(func(h *History) { + t.Logf("%+v\n", h) + }) + go func() { + for { + Send(&History{ + Module: "test", + Type: INFO, + Message: "testing", + Body: time.Now().String(), + Caller: util.Caller(2), + }) + time.Sleep(time.Second) + } + }() + + time.Sleep(time.Second * 20) + Stop() + t.Log("stoped") + time.Sleep(time.Second * 2) +} diff --git a/history/service.go b/history/service.go new file mode 100644 index 0000000..e561d71 --- /dev/null +++ b/history/service.go @@ -0,0 +1,34 @@ +package history + +import ( + "github.com/rs/zerolog/log" + "github.com/spf13/viper" + "kumoly.io/kumoly/app/store" + "kumoly.io/kumoly/app/system" +) + +type Service struct { + system.BaseService +} + +func (srv Service) GetName() string { return "history.Service" } +func (srv Service) IsService() bool { return true } +func (srv Service) Init() error { + PROD = viper.GetBool("prod") + l := log.With().Str("mod", "history"). + Str("service", "history.Service"). + Logger() + l.Debug().Msg("Migrating database for history.Service ...") + if err := store.Migrate(&History{}); err != nil { + l.Error().Err(err).Msg("Migrating database") + return err + } + return nil +} +func (srv Service) Main() error { + Start(DBReceiver) + return nil +} +func (srv Service) Del() { + Stop() +} diff --git a/messenger/base.gohtml b/messenger/base.gohtml new file mode 100644 index 0000000..4adfac3 --- /dev/null +++ b/messenger/base.gohtml @@ -0,0 +1,476 @@ + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/messenger/messenger.go b/messenger/messenger.go new file mode 100644 index 0000000..8393a7d --- /dev/null +++ b/messenger/messenger.go @@ -0,0 +1,5 @@ +package messenger + +func init() { + +} diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..e8149a4 --- /dev/null +++ b/run.sh @@ -0,0 +1,9 @@ + +export APP_SERVER_HOST=127.0.0.1 +export APP_SERVER_PORT=8000 +export APP_LOG_LEVEL=-1 +export APP_PROD=false +export APP_LOG_PRETTY=true +export APP_DB_TYPE=sqlite +export APP_DATA=work +go run cmd/test/main.go \ No newline at end of file diff --git a/system/helper.go b/system/helper.go index 243843a..ac27e9a 100644 --- a/system/helper.go +++ b/system/helper.go @@ -9,7 +9,7 @@ import ( type BaseService struct{} func (srv BaseService) GetName() string { return "base" } -func (srv BaseService) GetDependencies() []string { return []string{""} } +func (srv BaseService) GetDependencies() []string { return []string{} } func (srv BaseService) IsService() bool { return false } func (srv BaseService) Init() error { return nil } func (srv BaseService) Load() error { return nil } diff --git a/system/setup.go b/system/setup.go index 753f44e..0aabf29 100644 --- a/system/setup.go +++ b/system/setup.go @@ -1,6 +1,7 @@ package system import ( + "fmt" "io/ioutil" "os" "path/filepath" @@ -42,6 +43,7 @@ func init() { viper.SetEnvKeyReplacer(replacer) viper.AutomaticEnv() viper.SetConfigType("json") + setup() } func setup() { @@ -60,9 +62,24 @@ func setup() { if cc, ok := i.(string); ok { c = cc } - // if len(c) > 0 { - - // } + if len(c) > 0 { + // shorten caller to mod/file:line + segs := strings.Split(c, ":") + file := segs[len(segs)-2] + short := file + skip := false + for i := len(file) - 1; i > 0; i-- { + if file[i] == '/' { + if !skip { + skip = true + continue + } + short = file[i+1:] + break + } + } + return fmt.Sprintf("%v:%v", short, segs[len(segs)-1]) + } return c }, }) diff --git a/system/system.go b/system/system.go index 01fea71..c6302a9 100644 --- a/system/system.go +++ b/system/system.go @@ -98,7 +98,7 @@ func New() *System { } func (sys *System) Start() { - setup() + // setup() sys.order() sys.status = sys_init go func() { diff --git a/util/logging.go b/util/logging.go index 80e92ea..2111582 100644 --- a/util/logging.go +++ b/util/logging.go @@ -7,11 +7,39 @@ import ( "runtime" ) +func Stack() string { + buf := make([]byte, 1024) + for { + n := runtime.Stack(buf, false) + if n < len(buf) { + return string(buf[:n]) + } + buf = make([]byte, 2*len(buf)) + } +} + func CallerFull(depth int) string { _, file, line, _ := runtime.Caller(depth) return fmt.Sprintf("%s:%d", file, line) } +func CallerMod(depth int) (mod, file string) { + _, f, l, _ := runtime.Caller(depth) + ptr := 0 + for i := len(f) - 1; i > 0; i-- { + if f[i] == '/' { + if ptr == 0 { + file = fmt.Sprintf("%v:%v", f[i+1:], l) + ptr = i + } else { + mod = f[i+1 : ptr] + break + } + } + } + return +} + func Caller(depth int) string { _, file, line, _ := runtime.Caller(depth) short := file diff --git a/util/logging_test.go b/util/logging_test.go new file mode 100644 index 0000000..4e456d6 --- /dev/null +++ b/util/logging_test.go @@ -0,0 +1,22 @@ +package util + +import ( + "fmt" + "testing" +) + +func TestStack(t *testing.T) { + fmt.Println(Stack()) +} + +func TestCallerFull(t *testing.T) { + fmt.Println(CallerFull(1)) +} + +func TestCallerMod(t *testing.T) { + fmt.Println(CallerMod(1)) +} + +func TestCaller(t *testing.T) { + fmt.Println(Caller(1)) +}