Bonjour,
Vous êtes nombreux à utiliser les triggers sous SQL Server pour ajouter des commandes et des actions basés sur des évènements se produisant sur une table de Project Server 2010.
Que ce soit pour alimenter une table externe ou envoyer une notification par mail, le trigger est une solution simple et efficace d’étendre les fonctionnalités de Project Server 2010, même si nous recommandons de l’utiliser avec parcimonie du fait de l’impact non négligeable qu’il peut avoir sur les performance de Project Server, pouvant dans un cas extrême, provoquer des deadlocks.
Mais le trigger peut aussi avoir un intérêt lorsqu’il faut chercher la cause d’une action dont on ne connait pas la cause.
Ainsi, prenons l’exemple d’un cas dans lequel des enregistrements sont supprimés d’une table, sans que l’on sache pourquoi, mais qui provoque des disparitions de lignes dans les Feuilles de temps ou dans l’affichage de Mes Tâches.
En fait, et je vous passe tous les détails de la recherche de cause, ces enregistrements sont supprimés de la tables MSP_TASKS_SAVED de la base Published, créant ainsi des enregistrements orphelins dans la tables MSP_ASSIGNMENTS_SAVED.
Comme nous n’avons de scénario pour reproduire à volonté ce phénomène, il nous reste le choix entre:
- Exécuter SQL Profiler en mode Ring pour loguer toute l’activité de cette base de données sur un temps donné et stopper cette trace dès que le problème est détecté
- Créer un trigger DDL (les trigger DML ne sont pas utilisables sur une action DELETE) qui logue l’action dans une table temporaire
- Utiliser le fonction d’Audit de SQL Server 2008 (et R2) pour loguer l’action mais aussi des informations complémentaire sur ce qui a déclencher le trigger
La première solution est la plus facile à mettre en place mais le résultat obtenu peut varier considérablement en fonction du l’activité sur la base de données et surtout, il ne faut pas arrêter la trace trop tard sous peine de perdre les informations intéressantes.
De plus, cette solution a un impact non négligeable sur les performances et ne peut donc pas être utilisée sur une longue période.
La deuxième solution est aussi très facile à implémenter mais le résultat va rester assez limité car on ne pourra obtenir que des informations succintes sur l’évènement : Quand et Qui. Mais impossible de connaitre le Quoi car la fonction EVENDATA de SQL ne peut être utilisée que dans un trigger DML qui, je le rappelle ne peut pas être associé à une action DELETE sur un table.
La dernière solution est donc la meilleure car en plus de pouvoir vous donner des informations sur le Quand et le Qui, elle va aussi vous indiquer le Quoi. C’est donc cette solution que je vais vous détailler:
Création du fichier de Log
La première étape consiste à créer le fichier de log où seront stockées les informations d’Audit:
usemaster
go
-- Create the server audit.
CREATESERVERAUDITAudit_mytrig
TOFILE (FILEPATH='C:\');
GO
-- Enable the server audit.
ALTERSERVERAUDITAudit_mytrig
WITH (STATE=ON);
GO
Création du Trigger
Pour créer le trigger, vous devez exécuter la procédure suivante:
USEPROJECTSERVER_PUBLISHED ;
GO
CREATEDATABASEAUDITSPECIFICATIONAudit_mytrig_Table
FORSERVERAUDITAudit_mytrig
ADD (DELETE
ONMSP_TASKS_SAVEDbydbo)
WITH (STATE=ON);
GO
A partir ce cette étape, toute action de DELETE sur la table MSP_TASKS_SAVED va écrire une information dans le fichier de log.
Récupérer les informations du fichier de log:
Pour lire le contenu du fichier de log, vous pouvez utiliser la procédure suivante:
USEmaster
GO
-- get the audit file
DECLARE@filepatternVARCHAR(300)
DECLARE@folderVARCHAR(255)
DECLARE@auditguidVARCHAR(36)
SELECT@auditguid=audit_guid,@folder=log_file_path
FROMsys.server_file_auditsWHEREname='Audit_mytrig'
SELECT@filepattern=@folder+'*_'+@auditguid+'*'
-- view the results
SELECTevent_time,session_id,a.nameASAction,c.class_type_descASObjectType,
f.server_principal_name,f.schema_name,f.OBJECT_NAME,f.statement,f.additional_information
FROMfn_get_audit_file(@filepattern,NULL,NULL)ASf
JOINsys.dm_audit_class_type_mapcONf.class_type=c.class_type
JOINsys.dm_audit_actionsaONf.action_id=a.action_id
ANDc.securable_class_desc=a.class_desc
WHEREf.action_id<>'AUSC'
ORDERBYevent_timeDESC,sequence_number
Voici un exemple de ce que la requête renvoie alors qu’un DELETE vient d’être exécuté sur la table MSP_TASKS_SAVED:
Vous remarquez qu’en plus des informations basiques du Quand et du Qui, on a aussi une information très intéressante sur le Quoi. Cela peut être une requête ou une Procédure Stockée. Dans ce dernier cas, le nom de la procédure stockée apparait dans la colonne Statement.
Conclusion:
En conclusion, on peut dire que cette fonction peut être très utile pour connaitre la raison d’un phénomène que l’on ne peut expliquer. Est-ce une requête ou une procédure stockée liée à du code personnalisé ? Est-ce du code lié à une action particulière faite dans Project Server ?
L’information Statement peut nous aider considérablement pour comprendre ce qu’il se passe et peut être un très bon point de départ à la recherche d’une cause ou d’un scénario de reproduction.
N’hésitez pas à commenter cet article.
Bonne journée,
Marc Biarnès