First commit - backup RDOC

This commit is contained in:
2026-02-20 07:20:32 -03:00
commit b7415f0586
259 changed files with 51707 additions and 0 deletions

View File

@@ -0,0 +1,575 @@
# Sistema de Logs e Notificações para RDO-C
# Gerencia logs detalhados e notificações em tempo real
# Uso: Import-Module .\scripts\logging-notifications.ps1
# Configurações globais de logging
$script:LogConfig = @{
LogDirectory = "logs"
MaxLogSize = 10MB
MaxLogFiles = 10
LogLevels = @("TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL")
DateFormat = "yyyy-MM-dd HH:mm:ss.fff"
EnableConsole = $true
EnableFile = $true
EnableNotifications = $true
NotificationTypes = @("desktop", "email", "webhook")
}
# Configurações de notificação
$script:NotificationConfig = @{
Desktop = @{
Enabled = $true
ShowSuccess = $false
ShowWarning = $true
ShowError = $true
Duration = 5000
}
Email = @{
Enabled = $false
SmtpServer = ""
Port = 587
Username = ""
Password = ""
From = ""
To = @()
Subject = "RDO-C Auto-Sync Notification"
}
Webhook = @{
Enabled = $false
Url = ""
Method = "POST"
Headers = @{}
AuthToken = ""
}
Slack = @{
Enabled = $false
WebhookUrl = ""
Channel = "#dev-notifications"
Username = "RDO-C Bot"
IconEmoji = ":robot_face:"
}
Discord = @{
Enabled = $false
WebhookUrl = ""
Username = "RDO-C Auto-Sync"
AvatarUrl = ""
}
}
# Cores para diferentes níveis de log
$script:LogColors = @{
TRACE = "DarkGray"
DEBUG = "Gray"
INFO = "White"
WARN = "Yellow"
ERROR = "Red"
FATAL = "Magenta"
SUCCESS = "Green"
}
# Emojis para notificações
$script:LogEmojis = @{
TRACE = "🔍"
DEBUG = "🐛"
INFO = ""
WARN = "⚠️"
ERROR = ""
FATAL = "💀"
SUCCESS = ""
SYNC = "🔄"
DEPLOY = "🚀"
GIT = "📝"
}
# Classe para gerenciar logs estruturados
class LogEntry {
[string]$Timestamp
[string]$Level
[string]$Category
[string]$Message
[hashtable]$Context
[string]$Source
[string]$Thread
[string]$SessionId
LogEntry([string]$level, [string]$message, [string]$category = "General", [hashtable]$context = @{}) {
$this.Timestamp = Get-Date -Format $script:LogConfig.DateFormat
$this.Level = $level.ToUpper()
$this.Category = $category
$this.Message = $message
$this.Context = $context
$this.Source = (Get-PSCallStack)[2].Command
$this.Thread = [System.Threading.Thread]::CurrentThread.ManagedThreadId
$this.SessionId = $env:RDO_SESSION_ID ?? (New-Guid).ToString().Substring(0,8)
}
[string] ToString() {
$contextStr = if ($this.Context.Count -gt 0) {
" | Context: $($this.Context | ConvertTo-Json -Compress)"
} else { "" }
return "[$($this.Timestamp)] [$($this.Level)] [$($this.Category)] [$($this.Source)] $($this.Message)$contextStr"
}
[hashtable] ToHashtable() {
return @{
timestamp = $this.Timestamp
level = $this.Level
category = $this.Category
message = $this.Message
context = $this.Context
source = $this.Source
thread = $this.Thread
session_id = $this.SessionId
}
}
}
# Inicializar sistema de logging
function Initialize-LoggingSystem {
param(
[string]$ConfigPath = "logging-config.json"
)
# Criar diretório de logs
if (-not (Test-Path $script:LogConfig.LogDirectory)) {
New-Item -ItemType Directory -Path $script:LogConfig.LogDirectory -Force | Out-Null
}
# Carregar configuração personalizada se existir
if (Test-Path $ConfigPath) {
try {
$customConfig = Get-Content $ConfigPath | ConvertFrom-Json
# Mesclar configurações
foreach ($key in $customConfig.PSObject.Properties.Name) {
if ($script:LogConfig.ContainsKey($key)) {
$script:LogConfig[$key] = $customConfig.$key
}
}
Write-LogEntry "INFO" "Configuração de logging carregada: $ConfigPath" "System"
} catch {
Write-LogEntry "WARN" "Falha ao carregar configuração: $($_.Exception.Message)" "System"
}
}
# Configurar ID da sessão
if (-not $env:RDO_SESSION_ID) {
$env:RDO_SESSION_ID = (New-Guid).ToString().Substring(0,8)
}
Write-LogEntry "INFO" "Sistema de logging inicializado - Sessão: $env:RDO_SESSION_ID" "System"
return $true
}
# Função principal de logging
function Write-LogEntry {
param(
[Parameter(Mandatory=$true)]
[ValidateSet("TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "SUCCESS")]
[string]$Level,
[Parameter(Mandatory=$true)]
[string]$Message,
[string]$Category = "General",
[hashtable]$Context = @{},
[string]$LogFile = "",
[switch]$NoConsole,
[switch]$NoFile,
[switch]$NoNotification
)
# Criar entrada de log
$logEntry = [LogEntry]::new($Level, $Message, $Category, $Context)
# Log no console
if ($script:LogConfig.EnableConsole -and -not $NoConsole) {
Write-ConsoleLog -LogEntry $logEntry
}
# Log em arquivo
if ($script:LogConfig.EnableFile -and -not $NoFile) {
Write-FileLog -LogEntry $logEntry -LogFile $LogFile
}
# Notificações
if ($script:LogConfig.EnableNotifications -and -not $NoNotification) {
Send-LogNotification -LogEntry $logEntry
}
return $logEntry
}
# Escrever log no console
function Write-ConsoleLog {
param([LogEntry]$LogEntry)
$color = $script:LogColors[$LogEntry.Level]
$emoji = $script:LogEmojis[$LogEntry.Level]
$prefix = "$emoji [$($LogEntry.Level)] [$($LogEntry.Category)]"
$message = "$prefix $($LogEntry.Message)"
Write-Host $message -ForegroundColor $color
# Mostrar contexto se disponível
if ($LogEntry.Context.Count -gt 0) {
$contextStr = $LogEntry.Context | ConvertTo-Json -Compress
Write-Host " Context: $contextStr" -ForegroundColor DarkGray
}
}
# Escrever log em arquivo
function Write-FileLog {
param(
[LogEntry]$LogEntry,
[string]$LogFile = ""
)
# Determinar arquivo de log
if (-not $LogFile) {
$date = Get-Date -Format "yyyy-MM-dd"
$LogFile = Join-Path $script:LogConfig.LogDirectory "rdo-auto-sync-$date.log"
} else {
$LogFile = Join-Path $script:LogConfig.LogDirectory $LogFile
}
try {
# Verificar rotação de logs
if (Test-Path $LogFile) {
$fileInfo = Get-Item $LogFile
if ($fileInfo.Length -gt $script:LogConfig.MaxLogSize) {
Rotate-LogFile -LogFile $LogFile
}
}
# Escrever entrada
$logLine = $LogEntry.ToString()
Add-Content -Path $LogFile -Value $logLine -Encoding UTF8
} catch {
Write-Host "❌ Erro ao escrever log: $($_.Exception.Message)" -ForegroundColor Red
}
}
# Rotacionar arquivos de log
function Rotate-LogFile {
param([string]$LogFile)
$directory = Split-Path $LogFile -Parent
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($LogFile)
$extension = [System.IO.Path]::GetExtension($LogFile)
# Mover arquivos existentes
for ($i = $script:LogConfig.MaxLogFiles - 1; $i -gt 0; $i--) {
$oldFile = Join-Path $directory "$baseName.$i$extension"
$newFile = Join-Path $directory "$baseName.$($i + 1)$extension"
if (Test-Path $oldFile) {
if ($i -eq ($script:LogConfig.MaxLogFiles - 1)) {
Remove-Item $oldFile -Force
} else {
Move-Item $oldFile $newFile -Force
}
}
}
# Mover arquivo atual
$rotatedFile = Join-Path $directory "$baseName.1$extension"
Move-Item $LogFile $rotatedFile -Force
Write-LogEntry "INFO" "Log rotacionado: $LogFile" "System"
}
# Enviar notificações
function Send-LogNotification {
param([LogEntry]$LogEntry)
# Filtrar por nível
$shouldNotify = switch ($LogEntry.Level) {
"SUCCESS" { $script:NotificationConfig.Desktop.ShowSuccess }
"WARN" { $script:NotificationConfig.Desktop.ShowWarning }
"ERROR" { $script:NotificationConfig.Desktop.ShowError }
"FATAL" { $true }
default { $false }
}
if (-not $shouldNotify) { return }
# Notificação desktop
if ($script:NotificationConfig.Desktop.Enabled) {
Send-DesktopNotification -LogEntry $LogEntry
}
# Notificação por email
if ($script:NotificationConfig.Email.Enabled) {
Send-EmailNotification -LogEntry $LogEntry
}
# Webhook genérico
if ($script:NotificationConfig.Webhook.Enabled) {
Send-WebhookNotification -LogEntry $LogEntry
}
# Slack
if ($script:NotificationConfig.Slack.Enabled) {
Send-SlackNotification -LogEntry $LogEntry
}
# Discord
if ($script:NotificationConfig.Discord.Enabled) {
Send-DiscordNotification -LogEntry $LogEntry
}
}
# Notificação desktop (Windows)
function Send-DesktopNotification {
param([LogEntry]$LogEntry)
try {
$emoji = $script:LogEmojis[$LogEntry.Level]
$title = "RDO-C Auto-Sync $emoji"
$message = "[$($LogEntry.Category)] $($LogEntry.Message)"
# Usar Windows Toast Notification
Add-Type -AssemblyName System.Windows.Forms
$notification = New-Object System.Windows.Forms.NotifyIcon
$notification.Icon = [System.Drawing.SystemIcons]::Information
$notification.BalloonTipTitle = $title
$notification.BalloonTipText = $message
$notification.Visible = $true
$notification.ShowBalloonTip($script:NotificationConfig.Desktop.Duration)
# Limpar após exibição
Start-Sleep -Milliseconds 100
$notification.Dispose()
} catch {
Write-Host "⚠️ Falha na notificação desktop: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
# Notificação Slack
function Send-SlackNotification {
param([LogEntry]$LogEntry)
try {
$emoji = $script:LogEmojis[$LogEntry.Level]
$color = switch ($LogEntry.Level) {
"SUCCESS" { "good" }
"WARN" { "warning" }
"ERROR" { "danger" }
"FATAL" { "danger" }
default { "#36a64f" }
}
$payload = @{
channel = $script:NotificationConfig.Slack.Channel
username = $script:NotificationConfig.Slack.Username
icon_emoji = $script:NotificationConfig.Slack.IconEmoji
attachments = @(
@{
color = $color
title = "$emoji RDO-C Auto-Sync - $($LogEntry.Level)"
text = $LogEntry.Message
fields = @(
@{
title = "Categoria"
value = $LogEntry.Category
short = $true
},
@{
title = "Timestamp"
value = $LogEntry.Timestamp
short = $true
}
)
footer = "RDO-C Auto-Sync"
ts = [int][double]::Parse((Get-Date -UFormat %s))
}
)
}
$json = $payload | ConvertTo-Json -Depth 4
Invoke-RestMethod -Uri $script:NotificationConfig.Slack.WebhookUrl -Method POST -Body $json -ContentType "application/json"
} catch {
Write-Host "⚠️ Falha na notificação Slack: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
# Notificação Discord
function Send-DiscordNotification {
param([LogEntry]$LogEntry)
try {
$emoji = $script:LogEmojis[$LogEntry.Level]
$color = switch ($LogEntry.Level) {
"SUCCESS" { 65280 } # Verde
"WARN" { 16776960 } # Amarelo
"ERROR" { 16711680 } # Vermelho
"FATAL" { 8388736 } # Roxo
default { 3447003 } # Azul
}
$payload = @{
username = $script:NotificationConfig.Discord.Username
avatar_url = $script:NotificationConfig.Discord.AvatarUrl
embeds = @(
@{
title = "$emoji RDO-C Auto-Sync - $($LogEntry.Level)"
description = $LogEntry.Message
color = $color
fields = @(
@{
name = "Categoria"
value = $LogEntry.Category
inline = $true
},
@{
name = "Fonte"
value = $LogEntry.Source
inline = $true
}
)
timestamp = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
footer = @{
text = "Sessão: $($LogEntry.SessionId)"
}
}
)
}
$json = $payload | ConvertTo-Json -Depth 4
Invoke-RestMethod -Uri $script:NotificationConfig.Discord.WebhookUrl -Method POST -Body $json -ContentType "application/json"
} catch {
Write-Host "⚠️ Falha na notificação Discord: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
# Funções de conveniência para diferentes categorias
function Write-GitLog {
param([string]$Level, [string]$Message, [hashtable]$Context = @{})
Write-LogEntry -Level $Level -Message $Message -Category "Git" -Context $Context
}
function Write-SyncLog {
param([string]$Level, [string]$Message, [hashtable]$Context = @{})
Write-LogEntry -Level $Level -Message $Message -Category "Sync" -Context $Context
}
function Write-DeployLog {
param([string]$Level, [string]$Message, [hashtable]$Context = @{})
Write-LogEntry -Level $Level -Message $Message -Category "Deploy" -Context $Context
}
function Write-WatchLog {
param([string]$Level, [string]$Message, [hashtable]$Context = @{})
Write-LogEntry -Level $Level -Message $Message -Category "FileWatch" -Context $Context
}
# Análise de logs
function Get-LogAnalysis {
param(
[string]$LogFile = "",
[int]$LastHours = 24,
[string[]]$Levels = @(),
[string[]]$Categories = @()
)
if (-not $LogFile) {
$date = Get-Date -Format "yyyy-MM-dd"
$LogFile = Join-Path $script:LogConfig.LogDirectory "rdo-auto-sync-$date.log"
}
if (-not (Test-Path $LogFile)) {
Write-Host "❌ Arquivo de log não encontrado: $LogFile" -ForegroundColor Red
return
}
$cutoffTime = (Get-Date).AddHours(-$LastHours)
$logs = Get-Content $LogFile | ForEach-Object {
if ($_ -match '\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] \[([A-Z]+)\] \[([^\]]+)\]') {
$timestamp = [DateTime]::ParseExact($matches[1], $script:LogConfig.DateFormat, $null)
if ($timestamp -gt $cutoffTime) {
@{
Timestamp = $timestamp
Level = $matches[2]
Category = $matches[3]
FullLine = $_
}
}
}
} | Where-Object { $_ -ne $null }
# Filtrar por níveis e categorias
if ($Levels.Count -gt 0) {
$logs = $logs | Where-Object { $_.Level -in $Levels }
}
if ($Categories.Count -gt 0) {
$logs = $logs | Where-Object { $_.Category -in $Categories }
}
# Estatísticas
$stats = @{
Total = $logs.Count
ByLevel = $logs | Group-Object Level | ForEach-Object { @{ $_.Name = $_.Count } }
ByCategory = $logs | Group-Object Category | ForEach-Object { @{ $_.Name = $_.Count } }
TimeRange = @{
Start = ($logs | Sort-Object Timestamp | Select-Object -First 1).Timestamp
End = ($logs | Sort-Object Timestamp | Select-Object -Last 1).Timestamp
}
}
Write-Host ""
Write-Host "📊 Análise de Logs - Últimas $LastHours horas" -ForegroundColor Cyan
Write-Host "============================================" -ForegroundColor Cyan
Write-Host "Total de entradas: $($stats.Total)" -ForegroundColor White
Write-Host ""
Write-Host "Por Nível:" -ForegroundColor Yellow
$stats.ByLevel | ForEach-Object {
$_.GetEnumerator() | ForEach-Object {
$emoji = $script:LogEmojis[$_.Key]
Write-Host " $emoji $($_.Key): $($_.Value)" -ForegroundColor White
}
}
Write-Host ""
Write-Host "Por Categoria:" -ForegroundColor Yellow
$stats.ByCategory | ForEach-Object {
$_.GetEnumerator() | ForEach-Object {
Write-Host " 📁 $($_.Key): $($_.Value)" -ForegroundColor White
}
}
return $stats
}
# Exportar funções
Export-ModuleMember -Function @(
'Initialize-LoggingSystem',
'Write-LogEntry',
'Write-GitLog',
'Write-SyncLog',
'Write-DeployLog',
'Write-WatchLog',
'Get-LogAnalysis',
'Send-LogNotification'
)
# Inicializar automaticamente se importado
if ($MyInvocation.InvocationName -eq 'Import-Module' -or $MyInvocation.InvocationName -eq '.') {
Initialize-LoggingSystem
}