117 lines
4.2 KiB
Go
117 lines
4.2 KiB
Go
|
|
// Файл: internal/storage/audit.go
|
|||
|
|
// Назначение: Аудит всех операций создания, изменения, удаления данных
|
|||
|
|
// с записью временной метки с точностью до миллисекунды
|
|||
|
|
|
|||
|
|
package storage
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"sync"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// AuditEntry представляет запись аудита
|
|||
|
|
type AuditEntry struct {
|
|||
|
|
ID string `msgpack:"id"`
|
|||
|
|
Timestamp int64 `msgpack:"timestamp"` // Unix миллисекунды
|
|||
|
|
TimestampStr string `msgpack:"timestamp_str"` // Человекочитаемая строка
|
|||
|
|
Operation string `msgpack:"operation"` // CREATE, UPDATE, DELETE, START, COMMIT, ABORT, CLUSTER
|
|||
|
|
DataType string `msgpack:"data_type"` // DATABASE, COLLECTION, DOCUMENT, FIELD, TUPLE, SESSION, TRANSACTION, CLUSTER
|
|||
|
|
Name string `msgpack:"name"` // Имя объекта
|
|||
|
|
Details map[string]interface{} `msgpack:"details"` // Детали операции
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AuditLogger управляет аудитом
|
|||
|
|
type AuditLogger struct {
|
|||
|
|
entries []AuditEntry
|
|||
|
|
mu sync.RWMutex
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var globalAuditLogger = &AuditLogger{
|
|||
|
|
entries: make([]AuditEntry, 0),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetCurrentTimestamp возвращает текущую временную метку с миллисекундами
|
|||
|
|
func GetCurrentTimestamp() (int64, string) {
|
|||
|
|
now := time.Now()
|
|||
|
|
timestampMs := now.UnixMilli()
|
|||
|
|
timestampStr := now.Format("2006-01-02 15:04:05.000")
|
|||
|
|
return timestampMs, timestampStr
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// LogAudit записывает событие в аудит
|
|||
|
|
func LogAudit(operation, dataType, name string, details map[string]interface{}) {
|
|||
|
|
timestampMs, timestampStr := GetCurrentTimestamp()
|
|||
|
|
|
|||
|
|
entry := AuditEntry{
|
|||
|
|
ID: fmt.Sprintf("%d", timestampMs),
|
|||
|
|
Timestamp: timestampMs,
|
|||
|
|
TimestampStr: timestampStr,
|
|||
|
|
Operation: operation,
|
|||
|
|
DataType: dataType,
|
|||
|
|
Name: name,
|
|||
|
|
Details: details,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
globalAuditLogger.mu.Lock()
|
|||
|
|
globalAuditLogger.entries = append(globalAuditLogger.entries, entry)
|
|||
|
|
globalAuditLogger.mu.Unlock()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetAuditLog возвращает копию лога аудита
|
|||
|
|
func GetAuditLog() []AuditEntry {
|
|||
|
|
globalAuditLogger.mu.RLock()
|
|||
|
|
defer globalAuditLogger.mu.RUnlock()
|
|||
|
|
|
|||
|
|
result := make([]AuditEntry, len(globalAuditLogger.entries))
|
|||
|
|
copy(result, globalAuditLogger.entries)
|
|||
|
|
return result
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AuditDatabaseOperation логирует операцию с базой данных
|
|||
|
|
func AuditDatabaseOperation(operation, dbName string) {
|
|||
|
|
LogAudit(operation, "DATABASE", dbName, map[string]interface{}{
|
|||
|
|
"database": dbName,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AuditCollectionOperation логирует операцию с коллекцией
|
|||
|
|
func AuditCollectionOperation(operation, dbName, collName string, settings interface{}) {
|
|||
|
|
LogAudit(operation, "COLLECTION", fmt.Sprintf("%s.%s", dbName, collName), map[string]interface{}{
|
|||
|
|
"database": dbName,
|
|||
|
|
"collection": collName,
|
|||
|
|
"settings": settings,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AuditDocumentOperation логирует операцию с документом
|
|||
|
|
func AuditDocumentOperation(operation, dbName, collName, docID string, fields map[string]interface{}) {
|
|||
|
|
LogAudit(operation, "DOCUMENT", fmt.Sprintf("%s.%s.%s", dbName, collName, docID), map[string]interface{}{
|
|||
|
|
"database": dbName,
|
|||
|
|
"collection": collName,
|
|||
|
|
"document_id": docID,
|
|||
|
|
"fields": fields,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AuditFieldOperation логирует операцию с полем
|
|||
|
|
func AuditFieldOperation(operation, dbName, collName, docID, fieldName string, value interface{}) {
|
|||
|
|
LogAudit(operation, "FIELD", fmt.Sprintf("%s.%s.%s.%s", dbName, collName, docID, fieldName), map[string]interface{}{
|
|||
|
|
"database": dbName,
|
|||
|
|
"collection": collName,
|
|||
|
|
"document_id": docID,
|
|||
|
|
"field": fieldName,
|
|||
|
|
"value": value,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AuditTupleOperation логирует операцию с кортежем
|
|||
|
|
func AuditTupleOperation(operation, dbName, collName, docID, tuplePath string) {
|
|||
|
|
LogAudit(operation, "TUPLE", fmt.Sprintf("%s.%s.%s.%s", dbName, collName, docID, tuplePath), map[string]interface{}{
|
|||
|
|
"database": dbName,
|
|||
|
|
"collection": collName,
|
|||
|
|
"document_id": docID,
|
|||
|
|
"tuple_path": tuplePath,
|
|||
|
|
})
|
|||
|
|
}
|