Les logs

Il faut bien commencer par quelque chose sur un projet, pour ma part j’ai l’habitude de m’attarder sur les logs, parce que sans eux, débuguer c’est l’enfer. Et comme en dev on passe 20% de notre temps à innover et 80% à débuguer, ça me paraissait essentiel.

Au menu:

  1. Créer un prompt pour que l’IA nous génère un script Powershell
  2. Envoyer le prompt à Claude.ai et ChatGPT, puis comparer les deux
  3. Faire des tests et un bilan des codes

Environnement de test

  • Un fichier .ps1 par fonction. Donc un pour Claude.ai et un pour ChatGPT.
  • Même contenu de test à savoir:
# Exemple d'utilisation classique en console
# Changer CustomLogClaude en CustomLogGPT
Write-CustomLogClaude -Message "This is a success message." -LogType "Success"
Write-CustomLogClaude -Message "This is an error message." -LogType "Error"
Write-CustomLogClaude -Message "This is a warning message." -LogType "Warning"
Write-CustomLogClaude -Message "This is a debug message." -LogType "Debug"

# Exemple depuis deux fonctions
function test {
    Get-Process | select -first 10 name,handles | % {
        Write-CustomLogClaude -Message $_.name -LogType (random "error","debug","success","warning")
    }
}

function test2 {
    Get-Process | select -first 10 name,handles | % {
        Write-CustomLogClaude -Message $_.name -LogType (random "error","debug","success","warning")
    }
}

test
test2

Prompt

Peux-tu générer une fonction Powershell permettant d'alimenter un fichier journal ?
Spécifications:
- Le nom du fichier de log doit être unique à la session Powershell
- Le nom du fichier de log doit porter le nom de la fonction en cours ou du script en cours
- Le nom du fichier de log doit contenir un horodatage
- Le contenu du fichier de log doit être horodaté
- On doit pouvoir spécifier le type de log (Success, Error, Warning, Debug)
- Un Write-Host avec coloration de la syntaxe doit être utilisé en fonction du type de log
- Si c'est un log de type Debug, le log doit aller dans un dossier dédié /debug

Claude.ai

# Fonction générée par Claude.ai
function Write-CustomLogClaude {
    param (
        [Parameter(Mandatory=$true)]
        [string]$Message,
        
        [Parameter(Mandatory=$false)]
        [ValidateSet('Success', 'Error', 'Warning', 'Debug')]
        [string]$LogType = 'Success'
    )

    # Obtenir le nom du script ou de la fonction en cours
    $callStack = Get-PSCallStack
    $callerName = if ($callStack.Length -gt 1) { $callStack[1].Command } else { "Interactive" }

    # Créer un nom de fichier unique pour la session
    $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
    $sessionId = [Guid]::NewGuid().ToString().Substring(0, 8)
    $logFileName = "${callerName}_${timestamp}_${sessionId}.log"

    # Définir le chemin du fichier de log
    $logPath = if ($LogType -eq 'Debug') {
        Join-Path $PWD "debug"
    } else {
        $PWD
    }

    # Créer le dossier debug si nécessaire
    if ($LogType -eq 'Debug' -and -not (Test-Path $logPath)) {
        New-Item -ItemType Directory -Path $logPath | Out-Null
    }

    $logFilePath = Join-Path $logPath $logFileName

    # Préparer le message de log
    $logTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "[$logTime] [$LogType] $Message"

    # Écrire dans le fichier de log
    Add-Content -Path $logFilePath -Value $logMessage

    # Définir la couleur pour Write-Host
    $color = switch ($LogType) {
        'Success' { 'Green' }
        'Error'   { 'Red' }
        'Warning' { 'Yellow' }
        'Debug'   { 'Cyan' }
        default   { 'White' }
    }

    # Afficher le message dans la console
    Write-Host $logMessage -ForegroundColor $color
}

Premier test en console

Alors ça foire mais parce que je ne suis pas dans la condition que j’ai décrit à l’IA. En effet je lance la commande depuis un prompt de VSCode, pas depuis un .ps1 ou une fonction importée. Je vais corriger ça.

Test en fonction

Si j’exécute les exemples donnés plus haut, le résultat est le suivant:

Fichiers de logs

Pour les logs, ce n’est pas au bon emplacement, cependant: C’est présent et complété ! Idem pour le Debug! Si on analyse le nom du fichier, on peut voir que la fin est composée d’un UID, mais il ne sert à rien étant donné que c’est l’horodatage complet qui permet d’être sûr à 99% d’avoir un log unique.

Beaucoup trop de logs sont générés, la faute au code mal (ou, pas) pensé.

# Obtenir le nom du script ou de la fonction en cours
$callStack = Get-PSCallStack
$callerName = if ($callStack.Length -gt 1) { $callStack[1].Command } else { "Interactive" }

$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$sessionId = [Guid]::NewGuid().ToString().Substring(0, 8)

$logFileName = "${callerName}_${timestamp}_${sessionId}.log"

Etant donné que $sessionId est nouveau à chaque exécution, même chose pour le callstack suivant ce qui appelle la fonction de log, pareil pour le timestamp…une execution = un log.

Donc, pour contourner ça, j’ai mis en place une variable script. Elle est créée une seule fois au début du script source et le sera conservée durant toute la session. Si le nom du caller (fonction/script) source change, le fichier de log change.

# Créer un nom de fichier unique pour la session
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$logFolderPath = join-path $env:APPDATA "Clixed\logs"
$script:sessionId = [Guid]::NewGuid().ToString()

if (-not $script:sessionId) {
	$script:sessionId = [Guid]::NewGuid().ToString()
}

if (-not $script:logFileName -or $script:logFileName -notlike "$($callerName)*") {
	$script:logFileName = "$callerName-$timestamp-$sessionID.log"
}

Correction

L’emplacement des logs n’est pas idéal car il le met en fonction de la position du terminal, rien de grave. J’ai corrigé ça en créant un dossier Clixed dans %appdata%. J’ai également corrigé le problème du “Scriptblock” lorsqu’on fait des tests en console.

Temps estimé des corrections: 30 minutes, pour avoir un truc qui est utilisable

Conclusion Claude.ai

Pas mal, mais très décevant. Connaissant le potentiel de cette IA depuis un moment, je suis surpris de son inefficacité ici. C’est sans doute lié au prompt, qui était volontairement léger.

ChatGPT

# Fonction générée par ChatGPT
function Write-CustomLogGPT {

    param (
        [string]$Message,
        [ValidateSet("Success", "Error", "Warning", "Debug")]
        [string]$LogType = "Debug"
    )
    # Déterminer le nom du fichier de log basé sur le nom de la fonction ou du script en cours et l'horodatage
    $scriptName = if ($PSCmdlet.MyInvocation.ScriptName) { [System.IO.Path]::GetFileNameWithoutExtension($PSCmdlet.MyInvocation.ScriptName) } else { "Session" }
    $timestamp = (Get-Date).ToString("yyyyMMdd-HHmmss")
    $sessionID = [guid]::NewGuid().ToString()
    $logFileName = "$scriptName-$timestamp-$sessionID.log"

    # Déterminer le chemin du fichier de log basé sur le type de log
    $logDirectory = if ($LogType -eq "Debug") { "$PSScriptRoot/debug" } else { $PSScriptRoot }
    if (-not (Test-Path $logDirectory)) {
        New-Item -Path $logDirectory -ItemType Directory | Out-Null
    }

    $logFilePath = Join-Path -Path $logDirectory -ChildPath $logFileName
    
    # Créer le message de log avec horodatage
    $timestampedMessage = "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") [$LogType] $Message"
  
    # Écrire dans le fichier de log
    Add-Content -Path $logFilePath -Value $timestampedMessage
  
    # Colorer la sortie dans la console en fonction du type de log
    switch ($LogType) {
        "Success" { Write-Host $timestampedMessage -ForegroundColor Green }
        "Error"   { Write-Host $timestampedMessage -ForegroundColor Red }
        "Warning" { Write-Host $timestampedMessage -ForegroundColor Yellow }
        "Debug"   { Write-Host $timestampedMessage -ForegroundColor Cyan }
    }
}

Premier test en console

Pas d’erreur !

Test en fonction

Tout est nickel.

Fichiers de logs

Même problème que Claude.ai, les logs sont créés à l’emplacement d’exécution et en masse. Mais ils fonctionnent !

Correction

J’ai corrigé l’emplacement des logs, leur surnombre et la manière de récupérer le préfix correspondant au nom du script/fonction en cours. C’est tout ! 5 minutes, sans prendre en compte que j’ai copier/coller du code de l’autre fonction de Claude.ai qui avait les mêmes problématiques.

Conclusion ChatGPT

Déjà, j’ai été très étonné: 36 lignes contre 52 pour Claude.ai. Et en plus, pas d’erreur à la première exécution! J’ai simplement modifié l’emplacement des logs pour le même que claude.ai. Mais beaucoup de choses se ressemblent, mêmes certaines variables sont identiques, j’imagine que les deux ont été entrainés avec des modèles similaires voire identique ou qu’ils partagent une base commune.

==Mention spéciale pour ChatGPT== qui a pris en compte un test d’existence du dossier de destination des logs et le créée si besoin. Ce qui n’est pas le cas de Claude.ai.

Ca valait le coup ?

Oui et non. En quelques minutes on peut avoir une fonction de logs assez bien faite. Cependant, on doit passer du temps à lire tout le bloc de code pour le corriger/adapter. Car non, une IA n’est pas capable avec une simple description de sortir une fonction aussi bien faite que ce que l’on imaginait. Mais le gros avantage, ici en tout cas, c’est qu’on a quand même quelque chose de plutôt bien construit à la base. C’est l’avantage des LLM qui apprennent d’un existant.

Pour les deux IA, la consigne “Le nom du fichier de log doit être unique à la session Powershell” a été source de confusion. Car chaque utilisation de la fonction créait un fichier de log unique. Ce qui était contre-productif.

Pour la suite, je tenterais une approche différente sur le prompt, peut-être en envoyant un algorithme complet.

Vous retrouverez les scripts dans mon repository Github ! https://github.com/qschweitzer/Clixed