Initial commit of Ocean's local development
This commit is contained in:
1 parent
9944a9e1df
commit
86451938ec
116 files changed
+3320
No files matched your search
@@ -0,0 +1,19 @@
|
||||
package Log
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log/Device"
|
||||
|
||||
/*
|
||||
Registering the logging devices. Normally, it is not necessary to call this function. To enable or disable a logging device,
|
||||
please use the configuration database instead. But if you create your own logging device, let say a e-mail logger, then you
|
||||
are able to use this function to activate your own logging device. It is save to use this function at any time and it is
|
||||
thread-save ;-)
|
||||
*/
|
||||
func AddLoggingDevice(device Device.Device) {
|
||||
|
||||
newDevice := device
|
||||
go func() {
|
||||
mutexDevices.Lock()
|
||||
devices.PushBack(newDevice)
|
||||
mutexDevices.Unlock()
|
||||
}()
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package Log
|
||||
|
||||
import "container/list"
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
func logEntryListToArray(data *list.List) (result []Meta.Entry) {
|
||||
count := data.Len()
|
||||
result = make([]Meta.Entry, count, count)
|
||||
position := 0
|
||||
for entry := data.Front(); entry != nil; entry = entry.Next() {
|
||||
result[position] = entry.Value.(Meta.Entry)
|
||||
position++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package Device
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
type Device interface {
|
||||
Log(logEntries []Meta.Entry)
|
||||
Flush()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
This is the logging device interface you have to fulfill to be a logging device :)
|
||||
*/
|
||||
package Device
|
||||
@@ -0,0 +1,7 @@
|
||||
package DeviceConsole
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log"
|
||||
|
||||
func ActivateLoggingDevice() {
|
||||
Log.AddLoggingDevice(Console{})
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package DeviceConsole
|
||||
|
||||
import "fmt"
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
type Console struct {
|
||||
}
|
||||
|
||||
func (dev Console) Log(entries []Meta.Entry) {
|
||||
for _, entry := range entries {
|
||||
fmt.Println(entry.Format())
|
||||
}
|
||||
}
|
||||
|
||||
func (dev Console) Flush() {
|
||||
// This is not necessary for a console logger
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
This is the console logging device. Any received entry is logged to the console.
|
||||
*/
|
||||
package DeviceConsole
|
||||
@@ -0,0 +1,7 @@
|
||||
package DeviceDatabase
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log"
|
||||
|
||||
func ActivateLoggingDevice() {
|
||||
Log.AddLoggingDevice(Database{})
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
This is the database logging device. The logging events will be cached and after a time span or a maximum amount of
|
||||
events, the logging entries are written to the database.
|
||||
*/
|
||||
package DeviceDatabase
|
||||
@@ -0,0 +1,14 @@
|
||||
package DeviceDatabase
|
||||
|
||||
func (dev Database) Flush() {
|
||||
mutexCacheFull.Lock()
|
||||
defer mutexCacheFull.Unlock()
|
||||
|
||||
amount := len(cache)
|
||||
for counter := 0; counter < amount; counter++ {
|
||||
write2Database(<-cache)
|
||||
}
|
||||
|
||||
logDB.Logout()
|
||||
logDBSession.Close()
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package DeviceDatabase
|
||||
|
||||
import "strconv"
|
||||
import "fmt"
|
||||
import "github.com/SommerEngineering/Ocean/ConfigurationDB"
|
||||
import "github.com/SommerEngineering/Ocean/Log"
|
||||
import LM "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
func init() {
|
||||
|
||||
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Starting now the database logging.`)
|
||||
defer Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Starting the database logging done.`)
|
||||
|
||||
initDatabase()
|
||||
if value, err := strconv.Atoi(ConfigurationDB.Read(`LogDBCacheSizeNumberOfEvents`)); err != nil {
|
||||
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityHigh, LM.ImpactUnknown, LM.MessageNameCONFIGURATION, `It was not possible to read the LogDBCacheSizeNumberOfEvents configuration.`, `The default value will be used.`, fmt.Sprintf(`Default value is %d.`, cacheSizeNumberOfEvents))
|
||||
} else {
|
||||
cacheSizeNumberOfEvents = value
|
||||
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `Configuration LogDBCacheSizeNumberOfEvents was loaded.`, fmt.Sprintf(`The value is %d.`, cacheSizeNumberOfEvents))
|
||||
}
|
||||
|
||||
if value, err := strconv.Atoi(ConfigurationDB.Read(`LogDBCacheSizeTime2FlushSeconds`)); err != nil {
|
||||
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityHigh, LM.ImpactUnknown, LM.MessageNameCONFIGURATION, `It was not possible to read the LogDBCacheSizeTime2FlushSeconds configuration.`, `The default value will be used.`, fmt.Sprintf(`Default value is %d.`, cacheSizeTime2FlushSeconds))
|
||||
} else {
|
||||
cacheSizeTime2FlushSeconds = value
|
||||
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `Configuration LogDBCacheSizeTime2FlushSeconds was loaded.`, fmt.Sprintf(`The value is %d.`, cacheSizeTime2FlushSeconds))
|
||||
}
|
||||
|
||||
cache = make(chan LogDBEntry, cacheSizeNumberOfEvents)
|
||||
initTimeout()
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package DeviceDatabase
|
||||
|
||||
import "labix.org/v2/mgo"
|
||||
import "github.com/SommerEngineering/Ocean/ConfigurationDB"
|
||||
import "github.com/SommerEngineering/Ocean/Log"
|
||||
import LM "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
func initDatabase() {
|
||||
|
||||
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameINIT, `Checking and init the logging database collection.`)
|
||||
defer Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameINIT, `Checking and init the logging database collection done.`)
|
||||
|
||||
databaseHost := ConfigurationDB.Read(`LogDBHost`)
|
||||
databaseDB := ConfigurationDB.Read(`LogDBDatabase`)
|
||||
databaseUsername := ConfigurationDB.Read(`LogDBUsername`)
|
||||
databasePassword := ConfigurationDB.Read(`LogDBPassword`)
|
||||
|
||||
// Connect to MongoDB:
|
||||
if newSession, errDial := mgo.Dial(databaseHost); errDial != nil {
|
||||
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to connect to the MongoDB host `+databaseHost, errDial.Error())
|
||||
return
|
||||
} else {
|
||||
logDBSession = newSession
|
||||
}
|
||||
|
||||
// Use the correct database:
|
||||
logDB = logDBSession.DB(databaseDB)
|
||||
|
||||
// Login:
|
||||
if errLogin := logDB.Login(databaseUsername, databasePassword); errLogin != nil {
|
||||
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to login the user `+databaseUsername, errLogin.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Get the collection:
|
||||
logDBCollection = logDB.C(`Logbook`)
|
||||
|
||||
//
|
||||
// Take care about all the indexes:
|
||||
//
|
||||
indexTimeUTC := mgo.Index{}
|
||||
indexTimeUTC.Key = []string{`TimeUTC`}
|
||||
logDBCollection.EnsureIndex(indexTimeUTC)
|
||||
|
||||
indexProject := mgo.Index{}
|
||||
indexProject.Key = []string{`Project`}
|
||||
logDBCollection.EnsureIndex(indexProject)
|
||||
|
||||
indexSender := mgo.Index{}
|
||||
indexSender.Key = []string{`Sender`}
|
||||
logDBCollection.EnsureIndex(indexSender)
|
||||
|
||||
indexCategory := mgo.Index{}
|
||||
indexCategory.Key = []string{`Category`}
|
||||
logDBCollection.EnsureIndex(indexCategory)
|
||||
|
||||
indexLevel := mgo.Index{}
|
||||
indexLevel.Key = []string{`Level`}
|
||||
logDBCollection.EnsureIndex(indexLevel)
|
||||
|
||||
indexSeverity := mgo.Index{}
|
||||
indexSeverity.Key = []string{`Severity`}
|
||||
logDBCollection.EnsureIndex(indexSeverity)
|
||||
|
||||
indexImpact := mgo.Index{}
|
||||
indexImpact.Key = []string{`Impact`}
|
||||
logDBCollection.EnsureIndex(indexImpact)
|
||||
|
||||
indexMessageName := mgo.Index{}
|
||||
indexMessageName.Key = []string{`MessageName`}
|
||||
logDBCollection.EnsureIndex(indexMessageName)
|
||||
|
||||
indexMessageDescription := mgo.Index{}
|
||||
indexMessageDescription.Key = []string{`MessageDescription`}
|
||||
logDBCollection.EnsureIndex(indexMessageDescription)
|
||||
|
||||
indexProjectTimeUTC := mgo.Index{}
|
||||
indexProjectTimeUTC.Key = []string{`Project`, `TimeUTC`}
|
||||
logDBCollection.EnsureIndex(indexProjectTimeUTC)
|
||||
|
||||
indexProjectSender := mgo.Index{}
|
||||
indexProjectSender.Key = []string{`Project`, `Sender`}
|
||||
logDBCollection.EnsureIndex(indexProjectSender)
|
||||
|
||||
indexProjectCategory := mgo.Index{}
|
||||
indexProjectCategory.Key = []string{`Project`, `Category`}
|
||||
logDBCollection.EnsureIndex(indexProjectCategory)
|
||||
|
||||
indexProjectLevel := mgo.Index{}
|
||||
indexProjectLevel.Key = []string{`Project`, `Level`}
|
||||
logDBCollection.EnsureIndex(indexProjectLevel)
|
||||
|
||||
indexProjectSeverity := mgo.Index{}
|
||||
indexProjectSeverity.Key = []string{`Project`, `Severity`}
|
||||
logDBCollection.EnsureIndex(indexProjectSeverity)
|
||||
|
||||
indexProjectImpact := mgo.Index{}
|
||||
indexProjectImpact.Key = []string{`Project`, `Impact`}
|
||||
logDBCollection.EnsureIndex(indexProjectImpact)
|
||||
|
||||
indexProjectMessageName := mgo.Index{}
|
||||
indexProjectMessageName.Key = []string{`Project`, `MessageName`}
|
||||
logDBCollection.EnsureIndex(indexProjectMessageName)
|
||||
|
||||
indexProjectMessageDescription := mgo.Index{}
|
||||
indexProjectMessageDescription.Key = []string{`Project`, `MessageDescription`}
|
||||
logDBCollection.EnsureIndex(indexProjectMessageDescription)
|
||||
|
||||
indexProjectTimeUTCSender := mgo.Index{}
|
||||
indexProjectTimeUTCSender.Key = []string{`Project`, `TimeUTC`, `Sender`}
|
||||
logDBCollection.EnsureIndex(indexProjectTimeUTCSender)
|
||||
|
||||
indexProjectTimeUTCCategory := mgo.Index{}
|
||||
indexProjectTimeUTCCategory.Key = []string{`Project`, `TimeUTC`, `Category`}
|
||||
logDBCollection.EnsureIndex(indexProjectTimeUTCCategory)
|
||||
|
||||
indexProjectTimeUTCLevel := mgo.Index{}
|
||||
indexProjectTimeUTCLevel.Key = []string{`Project`, `TimeUTC`, `Level`}
|
||||
logDBCollection.EnsureIndex(indexProjectTimeUTCLevel)
|
||||
|
||||
indexProjectTimeUTCSeverity := mgo.Index{}
|
||||
indexProjectTimeUTCSeverity.Key = []string{`Project`, `TimeUTC`, `Severity`}
|
||||
logDBCollection.EnsureIndex(indexProjectTimeUTCSeverity)
|
||||
|
||||
indexProjectTimeUTCImpact := mgo.Index{}
|
||||
indexProjectTimeUTCImpact.Key = []string{`Project`, `TimeUTC`, `Impact`}
|
||||
logDBCollection.EnsureIndex(indexProjectTimeUTCImpact)
|
||||
|
||||
indexProjectTimeUTCMessageName := mgo.Index{}
|
||||
indexProjectTimeUTCMessageName.Key = []string{`Project`, `TimeUTC`, `MessageName`}
|
||||
logDBCollection.EnsureIndex(indexProjectTimeUTCMessageName)
|
||||
|
||||
indexProjectTimeUTCMessageDescription := mgo.Index{}
|
||||
indexProjectTimeUTCMessageDescription.Key = []string{`Project`, `TimeUTC`, `MessageDescription`}
|
||||
logDBCollection.EnsureIndex(indexProjectTimeUTCMessageDescription)
|
||||
|
||||
indexTimeUTCSender := mgo.Index{}
|
||||
indexTimeUTCSender.Key = []string{`TimeUTC`, `Sender`}
|
||||
logDBCollection.EnsureIndex(indexTimeUTCSender)
|
||||
|
||||
indexTimeUTCCategory := mgo.Index{}
|
||||
indexTimeUTCCategory.Key = []string{`TimeUTC`, `Category`}
|
||||
logDBCollection.EnsureIndex(indexTimeUTCCategory)
|
||||
|
||||
indexTimeUTCLevel := mgo.Index{}
|
||||
indexTimeUTCLevel.Key = []string{`TimeUTC`, `Level`}
|
||||
logDBCollection.EnsureIndex(indexTimeUTCLevel)
|
||||
|
||||
indexTimeUTCSeverity := mgo.Index{}
|
||||
indexTimeUTCSeverity.Key = []string{`TimeUTC`, `Severity`}
|
||||
logDBCollection.EnsureIndex(indexTimeUTCSeverity)
|
||||
|
||||
indexTimeUTCImpact := mgo.Index{}
|
||||
indexTimeUTCImpact.Key = []string{`TimeUTC`, `Impact`}
|
||||
logDBCollection.EnsureIndex(indexTimeUTCImpact)
|
||||
|
||||
indexTimeUTCMessageName := mgo.Index{}
|
||||
indexTimeUTCMessageName.Key = []string{`TimeUTC`, `MessageName`}
|
||||
logDBCollection.EnsureIndex(indexTimeUTCMessageName)
|
||||
|
||||
indexTimeUTCMessageDescription := mgo.Index{}
|
||||
indexProjectTimeUTCMessageDescription.Key = []string{`TimeUTC`, `MessageDescription`}
|
||||
logDBCollection.EnsureIndex(indexTimeUTCMessageDescription)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package DeviceDatabase
|
||||
|
||||
import "time"
|
||||
import "github.com/SommerEngineering/Ocean/Shutdown"
|
||||
|
||||
// Case: The cache is full
|
||||
func cacheFull() {
|
||||
mutexCacheFull.Lock()
|
||||
defer mutexCacheFull.Unlock()
|
||||
|
||||
if len(cache) < cacheSizeNumberOfEvents {
|
||||
return
|
||||
}
|
||||
|
||||
for counter := 0; counter < cacheSizeNumberOfEvents; counter++ {
|
||||
write2Database(<-cache)
|
||||
}
|
||||
}
|
||||
|
||||
// Case: Time out
|
||||
func initTimeout() {
|
||||
|
||||
go func() {
|
||||
for {
|
||||
|
||||
if Shutdown.IsDown() {
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Duration(cacheSizeTime2FlushSeconds) * time.Second)
|
||||
mutexCacheFull.Lock()
|
||||
amount := len(cache)
|
||||
for counter := 0; counter < amount; counter++ {
|
||||
write2Database(<-cache)
|
||||
}
|
||||
mutexCacheFull.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package DeviceDatabase
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
type Database struct {
|
||||
}
|
||||
|
||||
func (dev Database) Log(entries []Meta.Entry) {
|
||||
|
||||
//
|
||||
// Can not log here to prevent endless loop (consumer is also producer)
|
||||
//
|
||||
|
||||
write2Cache(entries)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package DeviceDatabase
|
||||
|
||||
import "time"
|
||||
|
||||
type LogDBEntry struct {
|
||||
TimeUTC time.Time `bson:"TimeUTC"`
|
||||
Project string `bson:"Project"`
|
||||
Sender string `bson:"Sender"`
|
||||
Category string `bson:"Category"`
|
||||
Level string `bson:"Level"`
|
||||
Severity string `bson:"Severity"`
|
||||
Impact string `bson:"Impact"`
|
||||
MessageName string `bson:"MessageName"`
|
||||
MessageDescription string `bson:"MessageDescription"`
|
||||
Parameters []string `bson:"Parameters"`
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package DeviceDatabase
|
||||
|
||||
import "sync"
|
||||
import "labix.org/v2/mgo"
|
||||
import LM "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
var (
|
||||
senderName LM.Sender = `System::Logger::Database`
|
||||
mutexCacheFull sync.Mutex = sync.Mutex{}
|
||||
cache chan LogDBEntry = nil
|
||||
cacheSizeNumberOfEvents int = 50
|
||||
cacheSizeTime2FlushSeconds int = 6
|
||||
logDB *mgo.Database = nil
|
||||
logDBSession *mgo.Session = nil
|
||||
logDBCollection *mgo.Collection = nil
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
package DeviceDatabase
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
func write2Cache(entries []Meta.Entry) {
|
||||
for _, entry := range entries {
|
||||
if len(cache) == cacheSizeNumberOfEvents {
|
||||
go cacheFull()
|
||||
}
|
||||
|
||||
logDBentry := LogDBEntry{}
|
||||
logDBentry.Category = Meta.FormatCategory(entry.Category)
|
||||
logDBentry.Impact = Meta.FormatImpact(entry.Impact)
|
||||
logDBentry.Level = Meta.FormatLevel(entry.Level)
|
||||
logDBentry.MessageDescription = entry.MessageDescription
|
||||
logDBentry.MessageName = string(entry.MessageName)
|
||||
logDBentry.Parameters = entry.Parameters
|
||||
logDBentry.Project = entry.Project
|
||||
logDBentry.Sender = string(entry.Sender)
|
||||
logDBentry.Severity = Meta.FormatSeverity(entry.Severity)
|
||||
logDBentry.TimeUTC = entry.Time
|
||||
cache <- logDBentry
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package DeviceDatabase
|
||||
|
||||
func write2Database(entry LogDBEntry) {
|
||||
if err := logDBCollection.Insert(entry); err != nil {
|
||||
// Can not log here to prevent endless loop (consumer is also producer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package Log
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
import "github.com/SommerEngineering/Ocean/Log/Device"
|
||||
|
||||
func deviceDelay(newEntry Meta.Entry) {
|
||||
defer checkDeviceDelaySize()
|
||||
|
||||
// Insert the new entry at the correct position (time)!
|
||||
for logEvent := deviceDelayBuffer.Front(); logEvent != nil; logEvent = logEvent.Next() {
|
||||
currentEvent := logEvent.Value.(Meta.Entry)
|
||||
if newEntry.Time.Before(currentEvent.Time) {
|
||||
|
||||
mutexDeviceDelays.Lock()
|
||||
deviceDelayBuffer.InsertBefore(newEntry, logEvent)
|
||||
mutexDeviceDelays.Unlock()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Default: Insert at the back!
|
||||
mutexDeviceDelays.Lock()
|
||||
deviceDelayBuffer.PushBack(newEntry)
|
||||
mutexDeviceDelays.Unlock()
|
||||
}
|
||||
|
||||
func checkDeviceDelaySize() {
|
||||
mutexDeviceDelays.Lock()
|
||||
if deviceDelayBuffer.Len() >= logDeviceDelayNumberEvents {
|
||||
dataArray := logEntryListToArray(deviceDelayBuffer)
|
||||
deviceDelayBuffer.Init()
|
||||
|
||||
mutexDevices.RLock()
|
||||
for entry := devices.Front(); entry != nil; entry = entry.Next() {
|
||||
dev := entry.Value.(Device.Device)
|
||||
go dev.Log(dataArray)
|
||||
}
|
||||
mutexDevices.RUnlock()
|
||||
}
|
||||
|
||||
mutexDeviceDelays.Unlock()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package Log
|
||||
|
||||
import "time"
|
||||
import "github.com/SommerEngineering/Ocean/Log/Device"
|
||||
|
||||
/*
|
||||
Please do not call this function your self! This function allows Ocean to flush the logging at the shutting down case.
|
||||
*/
|
||||
func Flush() {
|
||||
mutexChannel.Lock()
|
||||
channelReady = false
|
||||
close(entriesBuffer)
|
||||
mutexChannel.Unlock()
|
||||
|
||||
// This is a bad design, but the scheduler need some time to write the last messages.
|
||||
time.Sleep(15 * time.Second)
|
||||
|
||||
mutexDeviceDelays.Lock()
|
||||
dataArray := logEntryListToArray(deviceDelayBuffer)
|
||||
deviceDelayBuffer.Init()
|
||||
mutexDeviceDelays.Unlock()
|
||||
|
||||
mutexDevices.RLock()
|
||||
for entry := devices.Front(); entry != nil; entry = entry.Next() {
|
||||
dev := entry.Value.(Device.Device)
|
||||
dev.Log(dataArray) // Want to wait to complete, therefore no new thread here
|
||||
go dev.Flush()
|
||||
}
|
||||
mutexDevices.RUnlock()
|
||||
|
||||
// This is a bad design, but the devices need (may) some time to write the last messages:
|
||||
time.Sleep(15 * time.Second)
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
package Log
|
||||
|
||||
import "time"
|
||||
import "fmt"
|
||||
import "strings"
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
func writeToChannel(logEntry Meta.Entry) {
|
||||
select {
|
||||
case entriesBuffer <- logEntry:
|
||||
case <-time.After(time.Duration(int64(logBufferTimeoutSeconds)) * time.Second):
|
||||
|
||||
// Warn: Can not log here to prevent endless loop and memory leak!
|
||||
fmt.Println(`Warning: Was not able to write to the logging buffer! Message=` + logEntry.Format())
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If, for any reason, you want to deliver a whole log entry to the logging system, then use this function to do so :) Normally,
|
||||
just use the LogFull() and LogShort() functions instead ;) There is one reason to use this: If you have to deliver old log
|
||||
events you have may imported or you have received a batch of log events of an remote system, etc. Because the LogShort() and
|
||||
LogFull() methods are setting the time to the current UTC time. Therefore, TakeEntry() is the only way to provide the time!
|
||||
*/
|
||||
func TakeEntry(logEntry Meta.Entry) {
|
||||
|
||||
logEntry = clearEntry(logEntry)
|
||||
mutexChannel.RLock()
|
||||
defer mutexChannel.RUnlock()
|
||||
|
||||
if !channelReady {
|
||||
|
||||
mutexPreChannelBuffer.Lock()
|
||||
defer mutexPreChannelBuffer.Unlock()
|
||||
|
||||
preChannelBuffer.PushBack(logEntry)
|
||||
return
|
||||
}
|
||||
|
||||
if !preChannelBufferUsed {
|
||||
preChannelBufferUsed = true
|
||||
mutexPreChannelBuffer.Lock()
|
||||
for entry := preChannelBuffer.Front(); entry != nil; entry = entry.Next() {
|
||||
writeToChannel(entry.Value.(Meta.Entry))
|
||||
}
|
||||
preChannelBuffer.Init()
|
||||
mutexPreChannelBuffer.Unlock()
|
||||
}
|
||||
|
||||
writeToChannel(logEntry)
|
||||
}
|
||||
|
||||
/*
|
||||
Create and deliver a full log message with all fields and with the current UTC time as logging time.
|
||||
|
||||
Sender The sender of this message (name of your component, like e.g. "APP::LOGIC::PAYPAL" etc.)
|
||||
Category Use "CategoryBUSINESS" for business events (new payments, etc.), use "CategoryUSER" for log events
|
||||
regarding users (e.g. new user registered, etc.) or "CategoryAPP" (for anything else).
|
||||
Level Choose a logging level.
|
||||
Severity Choose a degree of severity.
|
||||
Impact Choose a degree of impact.
|
||||
MessageName Choose a message name. This is like a common category for this event!
|
||||
Description The logging message you want to deliver.
|
||||
Parameters Provide as many additional parameters (type string) as you need.
|
||||
*/
|
||||
func LogFull(sender Meta.Sender, category Meta.Category, level Meta.Level, severity Meta.Severity, impact Meta.Impact, messageName Meta.MessageName, messageDescription string, parameters ...string) {
|
||||
|
||||
entry := Meta.Entry{}
|
||||
entry.Project = projectName
|
||||
entry.Time = time.Now().UTC()
|
||||
entry.Category = category
|
||||
entry.Level = level
|
||||
entry.MessageDescription = messageDescription
|
||||
entry.MessageName = messageName
|
||||
entry.Parameters = parameters
|
||||
entry.Severity = severity
|
||||
entry.Impact = impact
|
||||
entry.Sender = sender
|
||||
|
||||
TakeEntry(entry)
|
||||
}
|
||||
|
||||
/*
|
||||
Create and deliver a short log message with the current UTC time as logging time. The fields severity and impact
|
||||
are both set to "none" value. Therefore, this short logging function does not fit for logging problems, errors etc.
|
||||
|
||||
Sender The sender of this message (name of your component, like e.g. "APP::LOGIC::PAYPAL" etc.)
|
||||
Category Use "CategoryBUSINESS" for business events (new payments, etc.), use "CategoryUSER" for log events
|
||||
regarding users (e.g. new user registered, etc.) or "CategoryAPP" (for anything else).
|
||||
Level Choose a logging level.
|
||||
MessageName Choose a message name. This is like a common category for this event!
|
||||
Description The logging message you want to deliver.
|
||||
Parameters Provide as many additional parameters (type string) as you need.
|
||||
*/
|
||||
func LogShort(sender Meta.Sender, category Meta.Category, level Meta.Level, messageName Meta.MessageName, messageDescription string, parameters ...string) {
|
||||
|
||||
entry := Meta.Entry{}
|
||||
entry.Project = projectName
|
||||
entry.Time = time.Now().UTC()
|
||||
entry.Category = category
|
||||
entry.Level = level
|
||||
entry.MessageDescription = messageDescription
|
||||
entry.MessageName = messageName
|
||||
entry.Parameters = parameters
|
||||
entry.Severity = Meta.SeverityNone
|
||||
entry.Impact = Meta.ImpactNone
|
||||
entry.Sender = sender
|
||||
|
||||
TakeEntry(entry)
|
||||
}
|
||||
|
||||
func clearEntry(entry Meta.Entry) (result Meta.Entry) {
|
||||
entry.MessageDescription = removeWhitespaces(entry.MessageDescription)
|
||||
entry.Parameters = clearParameters(entry.Parameters)
|
||||
result = entry
|
||||
return
|
||||
}
|
||||
|
||||
func clearParameters(oldParameters []string) (result []string) {
|
||||
for n := 0; n < len(oldParameters); n++ {
|
||||
oldParameters[n] = removeWhitespaces(oldParameters[n])
|
||||
}
|
||||
|
||||
result = oldParameters
|
||||
return
|
||||
}
|
||||
|
||||
func removeWhitespaces(text string) (result string) {
|
||||
text = strings.Replace(text, "\n", ` `, -1)
|
||||
text = strings.Replace(text, "\t", ` `, -1)
|
||||
text = strings.Replace(text, "\r", ``, -1)
|
||||
|
||||
result = text
|
||||
return
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package Log
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
import "strconv"
|
||||
import "container/list"
|
||||
import "sync"
|
||||
import "path/filepath"
|
||||
import "os"
|
||||
import "io/ioutil"
|
||||
import "strings"
|
||||
|
||||
func readProjectName() {
|
||||
if currentDir, dirError := os.Getwd(); dirError != nil {
|
||||
panic(`Can not read the current working directory and therefore can not read the project name!`)
|
||||
} else {
|
||||
filename := filepath.Join(currentDir, `project.name`)
|
||||
if _, errFile := os.Stat(filename); errFile != nil {
|
||||
if os.IsNotExist(errFile) {
|
||||
panic(`Can not read the project name file 'project.name': File not found!`)
|
||||
} else {
|
||||
panic(`Can not read the project name file 'project.name': ` + errFile.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if projectNameBytes, errRead := ioutil.ReadFile(filename); errRead != nil {
|
||||
panic(`Can not read the project name file 'project.name': ` + errRead.Error())
|
||||
} else {
|
||||
projectName = string(projectNameBytes)
|
||||
projectName = strings.TrimSpace(projectName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
readProjectName()
|
||||
mutexDeviceDelays = sync.Mutex{}
|
||||
mutexPreChannelBuffer = sync.Mutex{}
|
||||
mutexChannel = sync.RWMutex{}
|
||||
preChannelBuffer = list.New()
|
||||
deviceDelayBuffer = list.New()
|
||||
devices = list.New()
|
||||
|
||||
initTimer()
|
||||
initCode()
|
||||
}
|
||||
|
||||
func initCode() {
|
||||
entriesBuffer = make(chan Meta.Entry, logBufferSize)
|
||||
|
||||
LogShort(senderName, Meta.CategorySYSTEM, Meta.LevelINFO, `Starting`, `The logger is now starting.`, `logBufferSize=`+strconv.Itoa(int(logBufferSize)), `logBufferTimeoutSeconds=`+strconv.Itoa(int(logBufferTimeoutSeconds)))
|
||||
go scheduler(entriesBuffer)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package Log
|
||||
|
||||
/*
|
||||
This function is used just internal by Ocean. Please do not call this function by your self!
|
||||
*/
|
||||
func LoggingIsReady() {
|
||||
channelReady = true
|
||||
preChannelBufferUsed = false
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package Meta
|
||||
|
||||
type Category byte
|
||||
|
||||
const (
|
||||
CategoryBUSINESS = Category(iota)
|
||||
CategorySYSTEM = Category(iota)
|
||||
CategoryAPP = Category(iota)
|
||||
CategoryUSER = Category(iota)
|
||||
)
|
||||
|
||||
func FormatCategory(cat Category) (result string) {
|
||||
switch cat {
|
||||
case CategoryBUSINESS:
|
||||
result = `C:BUSINESS`
|
||||
case CategoryAPP:
|
||||
result = `C:APP`
|
||||
case CategorySYSTEM:
|
||||
result = `C:SYSTEM`
|
||||
case CategoryUSER:
|
||||
result = `C:USER`
|
||||
default:
|
||||
result = `C:N/A`
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package Meta
|
||||
|
||||
import "time"
|
||||
|
||||
type Entry struct {
|
||||
Project string
|
||||
Time time.Time
|
||||
Sender Sender
|
||||
Category Category
|
||||
Level Level
|
||||
Severity Severity
|
||||
Impact Impact
|
||||
MessageName MessageName
|
||||
MessageDescription string
|
||||
Parameters []string
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package Meta
|
||||
|
||||
import "fmt"
|
||||
import "time"
|
||||
import "strconv"
|
||||
import "strings"
|
||||
|
||||
func (entry Entry) Format() (result string) {
|
||||
|
||||
lenSender := len(entry.Sender)
|
||||
if lenSender > 40 {
|
||||
lenSender = 40
|
||||
}
|
||||
|
||||
lenMessageName := len(entry.MessageName)
|
||||
if lenMessageName > 26 {
|
||||
lenMessageName = 26
|
||||
}
|
||||
|
||||
lenProject := len(entry.Project)
|
||||
if lenProject > 10 {
|
||||
lenProject = 10
|
||||
}
|
||||
|
||||
messageDescription := entry.MessageDescription
|
||||
messageDescription = strings.Replace(messageDescription, `\n`, ` `, -1)
|
||||
messageDescription = strings.Replace(messageDescription, `\t`, ` `, -1)
|
||||
messageDescription = strings.Replace(messageDescription, `\r`, ` `, -1)
|
||||
|
||||
result = fmt.Sprintf(` [■] P:%10s [■] %s [■] %10s [■] %11s [■] %10s [■] %10s [■] sender: %-40s [■] name: %-26s [■] %s [■]`, entry.Project[:lenProject], formatTime(entry.Time), FormatCategory(entry.Category), FormatLevel(entry.Level), FormatSeverity(entry.Severity), FormatImpact(entry.Impact), entry.Sender[:lenSender], entry.MessageName[:lenMessageName], messageDescription)
|
||||
|
||||
for _, param := range entry.Parameters {
|
||||
|
||||
paramText := param
|
||||
paramText = strings.Replace(paramText, `\n`, ` `, -1)
|
||||
paramText = strings.Replace(paramText, `\t`, ` `, -1)
|
||||
paramText = strings.Replace(paramText, `\r`, ` `, -1)
|
||||
|
||||
result = fmt.Sprintf(`%s %s [■]`, result, paramText)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func formatTime(t1 time.Time) (result string) {
|
||||
var year int = t1.Year()
|
||||
var month int = int(t1.Month())
|
||||
var day int = int(t1.Day())
|
||||
var minutes int = int(t1.Minute())
|
||||
var hours int = int(t1.Hour())
|
||||
var seconds int = int(t1.Second())
|
||||
var milliseconds int = int(float64(t1.Nanosecond()) / 1000000.0)
|
||||
|
||||
var monthText, dayText, minutesText, hoursText, secondsText, millisecondsText string
|
||||
|
||||
if month >= 1 && month <= 9 {
|
||||
monthText = fmt.Sprintf(`0%d`, month)
|
||||
} else {
|
||||
monthText = strconv.Itoa(month)
|
||||
}
|
||||
|
||||
if day >= 1 && day <= 9 {
|
||||
dayText = fmt.Sprintf(`0%d`, day)
|
||||
} else {
|
||||
dayText = strconv.Itoa(day)
|
||||
}
|
||||
|
||||
if minutes >= 0 && minutes <= 9 {
|
||||
minutesText = fmt.Sprintf(`0%d`, minutes)
|
||||
} else {
|
||||
minutesText = strconv.Itoa(minutes)
|
||||
}
|
||||
|
||||
if hours >= 0 && hours <= 9 {
|
||||
hoursText = fmt.Sprintf(`0%d`, hours)
|
||||
} else {
|
||||
hoursText = strconv.Itoa(hours)
|
||||
}
|
||||
|
||||
if seconds >= 0 && seconds <= 9 {
|
||||
secondsText = fmt.Sprintf(`0%d`, seconds)
|
||||
} else {
|
||||
secondsText = strconv.Itoa(seconds)
|
||||
}
|
||||
|
||||
if milliseconds >= 0 && milliseconds <= 9 {
|
||||
millisecondsText = fmt.Sprintf(`00%d`, milliseconds)
|
||||
} else if milliseconds >= 10 && milliseconds <= 99 {
|
||||
millisecondsText = fmt.Sprintf(`0%d`, milliseconds)
|
||||
} else {
|
||||
millisecondsText = strconv.Itoa(milliseconds)
|
||||
}
|
||||
|
||||
result = fmt.Sprintf(`%d%s%s %s%s%s.%s`, year, monthText, dayText, hoursText, minutesText, secondsText, millisecondsText)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package Meta
|
||||
|
||||
type Impact byte
|
||||
|
||||
const (
|
||||
ImpactNone = Impact(iota)
|
||||
ImpactLow = Impact(iota)
|
||||
ImpactMiddle = Impact(iota)
|
||||
ImpactHigh = Impact(iota)
|
||||
ImpactCritical = Impact(iota)
|
||||
ImpactUnknown = Impact(iota)
|
||||
)
|
||||
|
||||
func FormatImpact(pri Impact) (result string) {
|
||||
switch pri {
|
||||
case ImpactCritical:
|
||||
result = `I:CRITICAL`
|
||||
case ImpactHigh:
|
||||
result = `I:HIGH`
|
||||
case ImpactLow:
|
||||
result = `I:LOW`
|
||||
case ImpactMiddle:
|
||||
result = `I:MIDDLE`
|
||||
case ImpactNone:
|
||||
result = `I:NONE`
|
||||
case ImpactUnknown:
|
||||
result = `I:UNKNOWN`
|
||||
default:
|
||||
result = `I:N/A`
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package Meta
|
||||
|
||||
type Level byte
|
||||
|
||||
const (
|
||||
LevelWARN = Level(iota)
|
||||
LevelDEBUG = Level(iota)
|
||||
LevelERROR = Level(iota)
|
||||
LevelINFO = Level(iota)
|
||||
LevelTALKATIVE = Level(iota)
|
||||
LevelSECURITY = Level(iota)
|
||||
)
|
||||
|
||||
func FormatLevel(lvl Level) (result string) {
|
||||
switch lvl {
|
||||
case LevelDEBUG:
|
||||
result = `L:DEBUG`
|
||||
case LevelERROR:
|
||||
result = `L:ERROR`
|
||||
case LevelINFO:
|
||||
result = `L:INFO`
|
||||
case LevelSECURITY:
|
||||
result = `L:SECURITY`
|
||||
case LevelTALKATIVE:
|
||||
result = `L:TALKATIVE`
|
||||
case LevelWARN:
|
||||
result = `L:WARN`
|
||||
default:
|
||||
result = `L:N/A`
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package Meta
|
||||
|
||||
type MessageName string
|
||||
|
||||
const (
|
||||
MessageNameSTARTUP = `Startup`
|
||||
MessageNameINIT = `Init`
|
||||
MessageNameSHUTDOWN = `Shutdown`
|
||||
MessageNameEXECUTE = `Execute`
|
||||
MessageNameDATABASE = `Database`
|
||||
MessageNameNETWORK = `Network`
|
||||
MessageNameLOGIN = `Login`
|
||||
MessageNameLOGOUT = `Logout`
|
||||
MessageNameSESSION = `Session`
|
||||
MessageNameTIMEOUT = `Timeout`
|
||||
MessageNameFILESYSTEM = `Filesystem`
|
||||
MessageNameCOMMUNICATION = `Communication`
|
||||
MessageNameWRITE = `Write`
|
||||
MessageNameREAD = `Read`
|
||||
MessageNameALGORITHM = `Algorithm`
|
||||
MessageNameCONFIGURATION = `Configuration`
|
||||
MessageNameTIMER = `Timer`
|
||||
MessageNameINPUT = `Input`
|
||||
MessageNameOUTPUT = `Output`
|
||||
MessageNameBROWSER = `Browser`
|
||||
MessageNameSECURITY = `Security`
|
||||
MessageNameNOTFOUND = `NotFound`
|
||||
MessageNameANALYSIS = `Analysis`
|
||||
MessageNameSTATE = `State`
|
||||
MessageNameGENERATOR = `Generator`
|
||||
MessageNamePRODUCER = `Producer`
|
||||
MessageNameCONSUMER = `Consumer`
|
||||
MessageNamePASSWORD = `Password`
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
package Meta
|
||||
|
||||
type Sender string
|
||||
@@ -0,0 +1,33 @@
|
||||
package Meta
|
||||
|
||||
type Severity byte
|
||||
|
||||
const (
|
||||
SeverityNone = Severity(iota)
|
||||
SeverityLow = Severity(iota)
|
||||
SeverityMiddle = Severity(iota)
|
||||
SeverityHigh = Severity(iota)
|
||||
SeverityCritical = Severity(iota)
|
||||
SeverityUnknown = Severity(iota)
|
||||
)
|
||||
|
||||
func FormatSeverity(pri Severity) (result string) {
|
||||
switch pri {
|
||||
case SeverityCritical:
|
||||
result = `S:CRITICAL`
|
||||
case SeverityHigh:
|
||||
result = `S:HIGH`
|
||||
case SeverityLow:
|
||||
result = `S:LOW`
|
||||
case SeverityMiddle:
|
||||
result = `S:MIDDLE`
|
||||
case SeverityNone:
|
||||
result = `S:NONE`
|
||||
case SeverityUnknown:
|
||||
result = `S:UNKNOWN`
|
||||
default:
|
||||
result = `S:N/A`
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package Log
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
import "time"
|
||||
|
||||
// Note: The scheduler is the consumer for the logging channel!
|
||||
func scheduler(logBuffer chan Meta.Entry) {
|
||||
|
||||
LogShort(senderName, Meta.CategorySYSTEM, Meta.LevelINFO, Meta.MessageNameSTARTUP, `The scheduler runs now.`)
|
||||
var stopNextTime = false
|
||||
|
||||
for {
|
||||
if stopNextTime {
|
||||
break
|
||||
}
|
||||
|
||||
nextEntry, ok := <-logBuffer
|
||||
|
||||
if !ok {
|
||||
// The channel was closed!
|
||||
stopNextTime = true
|
||||
nextEntry = Meta.Entry{}
|
||||
nextEntry.Project = projectName
|
||||
nextEntry.Time = time.Now().UTC()
|
||||
nextEntry.Sender = senderName
|
||||
nextEntry.Category = Meta.CategorySYSTEM
|
||||
nextEntry.Level = Meta.LevelWARN
|
||||
nextEntry.Severity = Meta.SeverityCritical
|
||||
nextEntry.Impact = Meta.ImpactNone
|
||||
nextEntry.MessageName = Meta.MessageNameCOMMUNICATION
|
||||
nextEntry.MessageDescription = `The logging channel was closed!`
|
||||
}
|
||||
|
||||
deviceDelay(nextEntry)
|
||||
}
|
||||
|
||||
LogFull(senderName, Meta.CategorySYSTEM, Meta.LevelWARN, Meta.SeverityCritical, Meta.ImpactNone, Meta.MessageNameSHUTDOWN, `The scheduler is down now.`)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package Log
|
||||
|
||||
/*
|
||||
This function is used just internal by Ocean to change some configuration afterwards, after the first runtime stage
|
||||
(transition from not configured state in to the desired configurated stage, after the configuration database is ready).
|
||||
Please do not call this function by your self!
|
||||
*/
|
||||
func SetBufferSize(bufferSize int) {
|
||||
logBufferSize = bufferSize
|
||||
}
|
||||
|
||||
/*
|
||||
This function is used just internal by Ocean to change some configuration afterwards, after the first runtime stage
|
||||
(transition from not configured state in to the desired configurated stage, after the configuration database is ready).
|
||||
Please do not call this function by your self!
|
||||
*/
|
||||
func SetTimeoutSeconds(timeoutSeconds int) {
|
||||
logBufferTimeoutSeconds = timeoutSeconds
|
||||
}
|
||||
|
||||
/*
|
||||
This function is used just internal by Ocean to change some configuration afterwards, after the first runtime stage
|
||||
(transition from not configured state in to the desired configurated stage, after the configuration database is ready).
|
||||
Please do not call this function by your self!
|
||||
*/
|
||||
func SetDeviceDelayNumberEvents(numberEvents int) {
|
||||
logDeviceDelayNumberEvents = numberEvents
|
||||
}
|
||||
|
||||
/*
|
||||
This function is used just internal by Ocean to change some configuration afterwards, after the first runtime stage
|
||||
(transition from not configured state in to the desired configurated stage, after the configuration database is ready).
|
||||
Please do not call this function by your self!
|
||||
*/
|
||||
func SetDeviceDelayTimeoutSeconds(seconds int) {
|
||||
logDeviceDelayTimeoutSeconds = seconds
|
||||
}
|
||||
|
||||
/*
|
||||
This function is used just internal by Ocean to change some configuration afterwards, after the first runtime stage
|
||||
(transition from not configured state in to the desired configurated stage, after the configuration database is ready).
|
||||
Please do not call this function by your self!
|
||||
*/
|
||||
func SetProjectName(project string) {
|
||||
projectName = project
|
||||
}
|
||||
|
||||
/*
|
||||
This function is used just internal by Ocean to change some configuration afterwards, after the first runtime stage
|
||||
(transition from not configured state in to the desired configurated stage, after the configuration database is ready).
|
||||
Please do not call this function by your self!
|
||||
*/
|
||||
func ApplyConfigurationChanges() {
|
||||
|
||||
mutexChannel.Lock()
|
||||
channelReady = false
|
||||
close(entriesBuffer)
|
||||
mutexChannel.Unlock()
|
||||
|
||||
initCode()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package Log
|
||||
|
||||
import "time"
|
||||
import "fmt"
|
||||
import "github.com/SommerEngineering/Ocean/Log/Device"
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
|
||||
func initTimer() {
|
||||
|
||||
if timerIsRunning == true {
|
||||
LogFull(senderName, Meta.CategorySYSTEM, Meta.LevelWARN, Meta.SeverityHigh, Meta.ImpactNone, Meta.MessageNameSTARTUP, `The logging timer is already running.`)
|
||||
return
|
||||
}
|
||||
|
||||
timerIsRunning = true
|
||||
LogShort(senderName, Meta.CategorySYSTEM, Meta.LevelINFO, Meta.MessageNameSTARTUP, `Create the logging timer now.`, fmt.Sprintf(`Timeout=%d seconds`, logDeviceDelayTimeoutSeconds))
|
||||
|
||||
go func() {
|
||||
|
||||
for {
|
||||
time.Sleep(time.Duration(logDeviceDelayTimeoutSeconds) * time.Second)
|
||||
|
||||
mutexDeviceDelays.Lock()
|
||||
dataArray := logEntryListToArray(deviceDelayBuffer)
|
||||
deviceDelayBuffer.Init()
|
||||
mutexDeviceDelays.Unlock()
|
||||
|
||||
mutexDevices.RLock()
|
||||
for entry := devices.Front(); entry != nil; entry = entry.Next() {
|
||||
dev := entry.Value.(Device.Device)
|
||||
go dev.Log(dataArray)
|
||||
}
|
||||
mutexDevices.RUnlock()
|
||||
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package Log
|
||||
|
||||
import "github.com/SommerEngineering/Ocean/Log/Meta"
|
||||
import "container/list"
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
entriesBuffer chan Meta.Entry = nil
|
||||
logBufferSize int = 500
|
||||
logBufferTimeoutSeconds int = 4
|
||||
logDeviceDelayNumberEvents int = 600
|
||||
logDeviceDelayTimeoutSeconds int = 5
|
||||
channelReady bool = false
|
||||
preChannelBufferUsed bool = false
|
||||
preChannelBuffer *list.List = nil
|
||||
deviceDelayBuffer *list.List = nil
|
||||
devices *list.List = nil
|
||||
mutexDeviceDelays sync.Mutex = sync.Mutex{}
|
||||
mutexPreChannelBuffer sync.Mutex = sync.Mutex{}
|
||||
mutexChannel sync.RWMutex = sync.RWMutex{}
|
||||
mutexDevices sync.RWMutex = sync.RWMutex{}
|
||||
timerIsRunning bool = false
|
||||
projectName string = `not set`
|
||||
senderName Meta.Sender = `System::Log`
|
||||
)
|
||||
Reference in new issue
Block a user