Fichier log pour une application liée à une base de données

Chrispi

Ce tutoriel propose de développer avec Lazarus une solution de traçage des actions réalisées dans une application fonctionnant sous Windows. L'application est liée à une base de données sans pour autant en être l'administratrice. La base sert alors aussi à stocker dans une table les actions qui seront restituées ensuite dans un fichier log. Une autre table sert à l'archivage, permettant ainsi de limiter la taille de ce fichier.

Commentez

- Titre : Fichier log pour une application liée à une base de données

- Auteur : Chrispi

- Parution : 27 mars 2021

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2021 Chrispi. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. à créer au niveau de la base de données

- III. Création des unités et des fiches

- IV. Les composants et leurs propriétés

- IV-A. La fiche Data

- IV-B. L'application

- V. Rôle des composants spécifiques

- VI. Le code

- VI-A. Ordonnancement des fiches

- VI-B. Le code de la fiche Data

- VI-C. Le code de l'application

- VII. Conclusion

- VIII. Remerciements

I - Introduction

Débutant : avant de passer à ce tutoriel, il est préférable d’étudier le tutoriel « Gestion d'une base de données MySQL » d’Alcatiz.

https://alcatiz.developpez.com/tutoriel/lazarus-mysql/

Ce tutoriel est destiné à montrer comment une application liée à une base de données peut générer son propre fichier log. Le principe est d'enregistrer dans une table de la base de données les événements que nous choisirons et qu'un utilisateur produira en utilisant l'application. Ensuite, ces traces seront exportées dans un fichier texte, le fichier des logs. Quand il deviendra trop imposant, trop lourd, les logs seront archivés dans une autre table et conservés pendant un temps que nous déterminerons au cours duquel il y a toujours la possibilité de les extraire si nécessaire. Les traces parvenues à échéance de ce temps seront effacées.

Il vous est maintenant proposé de créer une application factice dont vous pourrez réutiliser les codes dans vos propres créations. Ici, ne seront pas reprises les premières étapes de création d’une application.

Le choix s’est porté sur une base de données de type MariaDB administrée avec phpMyAdmin.

Pour que l’application fonctionne, il faut que le serveur et la base de données soient actifs.

Pour utiliser MariaDB, il est nécessaire de mettre le fichier libmysql.dll dans le dossier contenant l’application. Il faut aussi utiliser le composant TmySQLxxConnection adapté à la version de MariaDB ainsi que bien renseigner le port.

II - à créer au niveau de la base de données

Dans la base de données, il faut créer une table t_log avec les colonnes : id, Horodate, NomPC, Ident, Action. Dans cette table t_log viendront s’inscrire les actions (événements, traces) choisies et réalisées dans l’application. Ainsi, pour chaque événement, nous aurons la date, l’heure, le nom du PC utilisé, l’identifiant de l’utilisateur de la session Windows et les actions faites dans l'application.

Pour horodater les logs, la date et l'heure sont générées au niveau de la base de données.

Voici le code SQL pour créer la table t_log :

CREATE TABLE `t_log` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`Horodate` DATETIME DEFAULT CURRENT_TIMESTAMP
NOT NULL,
`NomPC` VARCHAR(20) NOT NULL,
`Ident` VARCHAR(20) NOT NULL,
`Action` VARCHAR(80) NOT NULL,
PRIMARY KEY (`id`))
COLLATE='utf8_general_ci';

Il faut aussi créer une autre table identique à la précédente que nous nommons t_archive. Elle servira à archiver les logs pendant une durée que nous fixerons dans le code.

Voici le code SQL pour créer la table t_archive :

CREATE TABLE `t_archive` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`Horodate` DATETIME DEFAULT CURRENT_TIMESTAMP
NOT NULL,
`NomPC` VARCHAR(20) NOT NULL,
`Ident` VARCHAR(20) NOT NULL,
`Action` VARCHAR(80) NOT NULL,
PRIMARY KEY (`id`))
COLLATE='utf8_general_ci';

III - Création des unités et des fiches

Après avoir enregistré le projet, nous passons à la création des unités et des fiches (formes) :

- Data et l'unité datamodule pour la fiche de liaison à la base de données ;

- FormMain et l'unité main pour la fiche support de l'application.

Pour Data, il faut créer un datamodule et pas une fiche classique.

IV - Les composants et leurs propriétés

Maintenant nous élaborons la fiche Data, puis FormMain la fiche (forme) de l'application, en disposant les composants nécessaires pour chacune d'elles et nous modifions leurs propriétés.

IV-A - La fiche Data

Pour pouvoir utiliser le composant TCSVExporter, il faut préalablement installer le paquet lazdbexport dans Lazarus.

Il faut choisir le composant de connexion à la base de données en adéquation avec la version de MariaDB.

Composant

Propriétés

TDataModule

Name : Data

TMySQL56Connection

Renseigner : DatabaseName, HostName, Password, Port, UserName,
Name : ConnectSQL,
Transaction : TransactSQL

TSQLTransaction

Database : ConnectSQL
Name : TransactSQL

TSQLQuery

Database : ConnectSQL,
Name : ReqSQLLog, Transaction : TransactSQL

TSQLQuery

Database : ConnectSQL,
Name : ReqSQLExpLog, Transaction : TransactSQL

TCSVExporter

Dataset : ReqSQLExpLog,
FileName : C:\Chemin du dossier de l’application\Fichlog.txt,
Name : ExportCSVLog

IV-B - L'application

Composants

Propriétés

TForm

Color : clMoneyGreen
Caption : TutoLOG
Name : FormMain
Position : poScreenCenter

TButton (Bouton A)

Name : BtnA,
Caption : A

TButton (Bouton B)

Name : BtnB,
Caption : B

TButton (Bouton Quitter)

Name : BtnQuit,
Caption : Quitter

V - Rôle des composants spécifiques

- ReqSQLLog sert à :

- enregistrer les actions (événements) dans la table t_log.

ReqSQLExpLog sert à :

- extraire les actions (événements) de la table t_log pour leur exportation sous forme de fichier texte pour créer et mettre à jour le fichier des logs ;

- archiver les enregistrements de t_log dans t_archive ;

- supprimer les enregistrements qui ont dépassé la limite de conservation.

Nous verrons par la suite qu'il faut définir la taille du fichier des logs pour déclencher leur archivage dans la table t_archive. Il sera aussi nécessaire de déterminer dans le code la durée maximale de conservation des enregistrements dans cette table.

Le composant d’export :

- ExportCSVLog sert à créer et alimenter le fichier des logs.

VI - Le code

Les fiches prêtes avec leurs composants paramétrés, nous passons maintenant au codage. Nous allons commencer par l'ordonnancement des fiches, puis nous nous attaquerons à l'élaboration du code de chacune d'elles.

VI-A - Ordonnancement des fiches

Une bonne pratique voudrait que nous ne chargions pas toutes les fiches au démarrage de l'application. Nous allons les ordonner en affichant dans Lazarus le code source en cliquant sur Projet et ensuite Voir le code source. Nous allons faire en sorte que ce soit la fiche de l'application qui apparaîtra la première au démarrage. En effet, s'il y avait dans le projet d'autres fiches, seules FormMain et Data seraient chargées d'emblée. Dans le respect d'une logique de connexion préalable à la base de données, Data sera créée avant FormMain.

program Tutolog;

{$mode objfpc}{$H+}

uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, main, lazdbexport, datamodule
{ you can add units after this };

{$R *.res}

begin
RequireDerivedFormResource:=True;
Application.Scaled:=True;
Application.Initialize;
Application.CreateForm(TData, Data);
Application.CreateForm(TFormMain, FormMain);
Application.Run;
end.

VI-B - Le code de la fiche Data

La fiche Data constitue une sorte d'interface entre la couche utilisateur de l'application et la couche métier, la base de données. Le code concernant cette fiche est créé dans l'unité datamodule. Nous allons préparer l'unité pour accueillir les procédures Log et ExpLog.

Nous déclarons les procédures que nous allons élaborer. Elles seront appelées depuis la fiche FormMain.

{ TData }

TData = class(TDataModule)
ConnectSQL: TMySQL56Connection;
ExportCSVLog: TCSVExporter;
ReqSQLExpLog: TSQLQuery;
ReqSQLLog: TSQLQuery;
TransactSQL: TSQLTransaction;
procedure DataModuleCreate(Sender: TObject);
procedure Log(Nompc,user,untext: String); //Procédure pour inscrire les actions dans t_log
procedure Explog(Sender: TObject); //Procédure pour exporter et archiver les logs

Nous déclarons les variables publiques :

- NomPc celle destinée au recueil du nom du PC de l'utilisateur ;

- User celle pour le recueil de l'identifiant de l'utilisateur de la session Windows.

public
NomPC: String; //Pour récupérer le nom du PC
User: String; //Pour récupérer l'identifiant de l'utilisateur de la session Windows

Il faut récupérer dès l'ouverture de l'application les variables d'environnement précédentes.

procedure TData.DataModuleCreate(Sender: TObject);
begin
NomPC:= Application.EnvironmentVariable['COMPUTERNAME']; // Récupération du nom du PC
User:= Application.EnvironmentVariable['USERNAME']; // Récupération de l'identifiant utilisateur de la session Windows
end;

Nous élaborons maintenant la procédure Log qui est appelée pour tracer chacune des actions que nous aurons choisies et que l'utilisateur fera en se servant de l'application. La variable untext est le libellé de l'action ou événement. à chacune de ses sollicitations, avec le composant ReqSQLLOG la procédure inscrit l'action (log) dans la table t_log ainsi que le nom du PC et l'identifiant de l'utilisateur. Comme stipulé antérieurement, l'horodatage se fait au niveau de la base de données.

procedure TData.Log(const Nompc,User,untext: String); //Inscription des actions dans la table t_log
begin
ReqSQLLOG.SQL.Text:= 'INSERT INTO t_log (NomPC, Ident, Action) VALUES (:pc, :id, :ac);';
ReqSQLLOG.ParamByName('pc').asString:= NomPC; //Nom du PC
ReqSQLLOG.ParamByName('id').asString:= User; //Identifiant utilisateur session Windows
ReqSQLLOG.ParamByName('ac').asString:= untext; //Libellé de l'action
ReqSQLLOG.ExecSQL;
end;

Nous construisons la procédure ExpLog qui est appelée à la fermeture de l'application. Elle s'appuie sur le composant ReqSQLExpLog. Dans un premier temps, les traces sont récupérées dans la table t_log pour être exportées avec le composant ExportCSVLog et ainsi créer et/ou alimenter le fichier Fichlog.txt. Ce dernier est « pesé ». Ici nous fixons sa taille à 50 000 octets. Quand la valeur devient supérieure à ce seuil, les logs sont transférés dans la table t_archive où ils seront conservés pendant une durée que nous paramétrons à 730 jours. Les logs parvenus à cette échéance seront effacés. Si besoin, pendant leur durée de conservation, ils pourront être extraits de la base de données.

procedure TData.Explog(Sender: TObject); //Export à la fermeture de l'application des actions dans le fichier log, archivage et purge de t_log
var
F: file of Byte; //Fichier à peser
taille: Integer;
begin
//Récupération des logs dans t_log
ReqSQLExpLOG.Close;
ReqSQLExpLOG.SQL.Text:= 'SELECT Horodate, NomPC, Ident, Action FROM t_log;';
ReqSQLExpLOG.Open;
//Création, mise à jour fichier des logs
ExportCSVLog.Execute;
//Identification du fichier des logs et instructions pour évaluation de sa taille
AssignFile(F, ExtractFilePath(paramstr(0))+'Fichlog.txt');
reset(F); //Positionnement du fichier en lecture
taille:= FileSize(F); //Récupération de la taille totale du fichier en octets
//Transfert selon le poids en octets du fichier log
if taille > 50000 then
begin
//Transfert du contenu de la table des logs dans la table d'archivage
ReqSQLExpLOG.SQL.Text:= 'INSERT INTO t_archive (Horodate, NomPC, Ident, Action) SELECT Horodate, NomPC, Ident, Action FROM t_log;'; //Insertion des logs dans la table d'archivage avant effacement de la table des logs
ReqSQLExpLOG.ExecSQL;
ReqSQLExpLOG.SQL.Text:= 'TRUNCATE t_log;'; //Effacement de la table des logs
ReqSQLExpLOG.ExecSQL;
end;
//Suppression dans t_archive des enregistrements (ici créés il y a 2 ans soit 730 jours)
ReqSQLExpLOG.SQL.Text:= 'DELETE FROM t_archive WHERE DATEDIFF(CURRENT_DATE,Horodate)>730;';
ReqSQLExpLOG.ExecSQL;
end;

VI-C - Le code de l'application

La fiche FormMain est le support de l'application. Le code concernant cette fiche est créé dans l'unité main.

Afin d'assurer le lien avec la base de données et par conséquent la fiche Data, nous déclarons datamodule dans les clauses uses au niveau de l'implémentation.

implementation

{$R *.lfm}

uses
datamodule;

Pour enregistrer une action de l'utilisateur, il faut associer à l'événement la procédure Log que nous avons élaborée dans l'unité datamodule. Nous le faisons ici pour le bouton A. Il ne faut pas oublier de libeller l’événement : 'Clic sur bouton A'. Il faut procéder de même pour le bouton B.

procedure TFormMain.BtnAClick(Sender: TObject); //Bouton A
begin
Data.Log(Data.NomPC,Data.User,'Clic sur bouton A'); //Appel de la procédure pour inscrire l'utilisation du bouton dans t_log
end;

Pour tracer l'utilisation du bouton Quitter, nous codons de la même manière que pour les autres boutons et nous y associons l'action Close pour quitter l'application.

procedure TFormMain.BtnQuitClick(Sender: TObject); //Bouton Quitter
begin
Data.Log(Data.NomPC,Data.User,'Clic sur bouton Quitter'); //Appel de la procédure pour inscrire l'utilisation du bouton dans t_log
Close;
end;

La fermeture de l'application appelle la procédure ExpLog que nous avons aussi créée dans l'unité datamodule. Cette procédure permet d'une part d'exporter au format .txt les traces enregistrées dans la table t_log. D'autre part, elle les archive dans t_archive quand le fichier Fichlog.txt est devenu trop volumineux. Et enfin, quand les traces atteignent la date d'échéance de leur conservation, elle les supprime. À noter, nous traçons aussi la fermeture de l'application comme nous pourrions le faire pour toute autre action.

procedure TFormMain.FormClose(Sender: TObject; var CloseAction: TCloseAction); //Export à la fermeture de l'application des actions dans le fichier log, archivage, etc.
begin
Data.Log(Data.NomPC,Data.User,'Fermeture application'); //Appel de la procédure pour inscrire la fermeture de l'application dans t_log
Data.ExpLog(Self); //Appel de la procédure d'export et d'archivage
Application.Terminate;
end;

VII - Conclusion

Nous voilà parvenus au terme de ce tutoriel.

Démarrez la base de données et lancez l'application. Appuyez sur les boutons A et B plusieurs fois, puis sur le bouton Quitter. Allez ouvrir le fichier Fichlog.txt qui s'est créé dans le dossier de l'application. Vous devriez obtenir quelque chose comme ça :

Le nécessaire étant fait dans la base de données et dans l'application. Vous avez compris que pour tracer les actions, il suffit de mettre le code d'appel de la procédure Log dans la procédure des boutons et autres composants pour lesquels vous aurez choisi de tracer l'utilisation. Il faut être vigilant à inscrire le libellé adéquat et à ne pas mettre le code après Close.

Vous avez aussi sûrement remarqué que pour générer le fichier des logs, le fichier créé n’est pas un fichier .csv, mais un fichier .txt malgré l’utilisation d’un composant TCSVExporter. Ceci ne pose aucun souci puisqu'un fichier .csv est aussi en quelque sorte un fichier texte. Si vous le souhaitez, vous pouvez également changer de séparateur dans la propriété FormatSettings : FieldDelimiter.

En termes de sécurité, si quelqu'un veut effacer ses traces dans le fichier des logs, même en supprimant tout simplement le fichier, celui-ci sera de nouveau généré automatiquement à la prochaine utilisation de l’application. Pour effacer complètement les traces, il faut posséder des droits d’administrateur sur la base de données pour intervenir sur les tables.

VIII - Remerciements

Je remercie gvasseur58 pour ses encouragements pour me lancer et SergioMaster, mon maître du code, dont la lecture technique m'a accompagné et aidé pour élaborer ce tutoriel. Je remercie aussi ClaudeLELOUP pour la relecture orthographique.