Audit instances SOA 11g 2/4 : Mediator via SQL/Java

Voici le 2ème article de la série concernant les audits des instances SOA. Dans le premier article, nous avons pu voir 2 alternatives à la console pour obtenir les audits/logs des instances SOA. Nous allons à présent faire un focus sur la méthode de récupération via SQL / Java des informations concernant les Mediators.

Correspondance des logs de la console et des tables

Tout d’abord, nous allons déterminer où se retrouvent les logs d’un Mediator visibles dans la console. Vous pouvez retrouver la liste des tables concernées et leur descriptif fonctionnel dans le 1er article.

schéma relation console / tables
schéma relation console / tables

Précisions sur les tables

Voici quelques précisions sur les tables que nous allons utiliser par la suite :

TABLE

DESCRIPTIF

MEDIATOR_INSTANCE

Cette table permettra de récupérer l’identifiant du mediator que l’on souhaite récupérer.On utilisera comme point d’entrée l’identifiant de l’instance de composite.

Contient 1 ligne par instance de mediator.

MEDIATOR_CASE

Non utilisée dans les exemples. Elle contient les informations générales des différents « case » du mediator

Contient 1 ligne par mediator case.

MEDIATOR_CASE_DETAIL

Table dans laquelle se retrouveront les logs généraux de chaque case.

Contient 1 ligne par mediator case.

MEDIATOR_AUDIT_DOCUMENT

Table dans laquelle on retrouvera les informations XML de certains case, comme les données échangées.

Contient de 0 à plusieurs lignes par mediator case. En effet, le message est découpé en plusieurs lignes (properties, headers, payload)

Ainsi qu’une représentation des jointures entre les tables (non exhaustif, représente les jointures utilisées dans les exemples, pourrait se faire par d’autres champs, notamment l’ECID) :

schéma jointure table utilisées
schéma jointure table utilisées

Lecture dans MEDIATOR_CASE_DETAIL

Dans cette table, les informations sont dans le champ AUDIT_TRAIL de type Blob. En l’état elles sont compressées. On utilisera donc la méthode utl_compress.lz_uncompress pour effectuer la décompression.

SELECT utl_compress.lz_uncompress(mcd.AUDIT_TRAIL) atd
FROM MEDIATOR_CASE_DETAIL mcd, MEDIATOR_INSTANCE mi
WHERE mcd.INSTANCE_ID=mi.ID
AND mi.COMPOSITE_INSTANCE_ID = myCompositeInstanceId ;

A ce stade, on peut voir que les données sont lisibles (via SQL Developer en précisant la lecture en mode texte). Voici un extrait de code Java pour lire simplement le contenu du Blob obtenu après décompression. Ici l’exemple suppose que l’on a mis en place un PreparedStatement en amont avec la requête précédente :

    ResultSet rset = stmt.executeQuery();
    while(rset.next())
    {
        Blob blob = rset.getBlob("atd");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        InputStream is =  blob.getBinaryStream();
        byte[] buffer = new byte[256];
        int count = 0;
        while ((count = is.read(buffer)) > 0)
        {
            baos.write(buffer,0,count);
        }
        String auditDetail = baos.toString();
        System.out.println("Mediator Audit Detail : ");
        System.out.println(audit);
    }

Le résultat ressemblera par exemple à ceci (raccourci) :

<case_trail>
  <event type="case" id="934B81A0154611E3AF69096A055FDA1C" parentId="9343B970154611E3AF69096A055FDA1C" caseName="BPELSample.bpelsample_client.process" date="1378287861442" auditId="9343E080154611E3AF69096A055FDA1C">
    <message>MediatorAudit_0#BPELSample.bpelsample_client.process</message>
  </event>
…
  <event type="sendReply" status="Completed" parentId="934B81A0154611E3AF69096A055FDA1C" date="1378287861658" auditId="936CC540154611E3AF69096A055FDA1C">
    <message>MediatorAudit_17#process#BPELSample.bpelsample_client</message>
  </event>
</case_trail>

On pourra si on le souhaite utiliser ce code Java pour le manipuler de manière plus simple, via le DOM :

// nécessaire d’ajouter en-tête pour parsage
audit += "<?xml version="1.0" encoding="UTF-8"?>" ;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource( new StringReader(audit)));
Element element = doc.getDocumentElement();

Lecture dans MEDIATOR_AUDIT_DOCUMENT

Dans cette table les éléments sont un peu différent selon leur type, mais toujours dans le champ DOCUMENT de type Blob.

Dans le cas des properties, les données correspondent à un objet java sérialisé (HashMap) puis compressé. Dans le cas d’un payload, il s’agit de XML Binaire. Reste le header pour lequel nous n’avons pas déterminer le contenu exact.

Dans un premier temps on va donc récupérer les éléments en les décompressants :

SELECT utl_compress.lz_uncompress(mad.DOCUMENT) doc, mad.*
FROM MEDIATOR_AUDIT_DOCUMENT mad, MEDIATOR_INSTANCE mi
WHERE mad.INSTANCE_ID=mi.ID
AND mi.COMPOSITE_INSTANCE_ID = myCompositeInstanceId ;

Ensuite on effectuera en java un traitement qui diffèrera selon le type. Désérialisation pour les properties, lecture de XML Binaire pour le payload :

    ResultSet rset = stmt.executeQuery();
    while(rset.next())
    {
        Blob blob = rset.getBlob("doc");
        String type = rset.getString("type");
        if (type.equals("properties")) {
          ObjectInputStream ois = new ObjectInputStream(blob.getBinaryStream());
          Object obj = ois.readObject();
          Map properties = (HashMap) obj;
          System.out.println("Mediator Audit Document (properties) : ");
          for (Object key : properties.keySet())
          {
            System.out.println("  Property "+ key + " : " + properties.get(key));
          }
        }
        else if (type.equals("payload")) {
          XMLDOMImplementation domimpl = new XMLDOMImplementation();
          BinXMLProcessor proc = BinXMLProcessorFactory.createProcessor();
          BinXMLStream inpbin = proc.createBinXMLStream(blob);
          BinXMLDecoder dec = inpbin.getDecoder();
          InfosetReader xmlreader = dec.getReader();
          XMLDocument doc = (XMLDocument) domimpl.createDocument(xmlreader);
          System.out.println("Mediator Audit Document (payload) : ");
          doc.print(System.out);
        }
        else {
          System.out.println("type not handled : "+type);
        }
    }

Le résultat ressemblera par exemple à ceci :

Mediator Audit Document (properties) :
  Property oracle.integration.platform.request.processed.headers : []
  Property tracking.compositeInstanceId : 290003
  Property tracking.ecid : 11d1def534ea1be0:-7a2d8ea5:140e82ff561:-8000-000000000000017a
  Property tracking.conversationId : null
  Property tracking.compositeInstanceCreatedTime : Wed Sep 04 11:44:21 CEST 2013
  Property MESH_METRICS : null
  Property transport.http.remoteAddress : 127.0.0.1
Mediator Audit Document (payload) :
<ns1:singleString xmlns:ns1="http://xmlns.oracle.com/singleString">Easy </ns1:singleString>

Conclusion

Grace à ces éléments, vous avez pu voir comment récupérer directement en base tous les éléments d’audit d’un Mediator (valide de 11.1.1.4 à 11.1.1.7).

Les requêtes fournies ici sont à titre d’exemple, elles peuvent remaniées pour mettre en place différents critères. La seule règle qu’il est fortement conseillé d’applique est de bien vérifier les plans d’exécution de vos requêtes, de bien utiliser les index. Une mauvaise requête peut être pénalisante pour la SOA-Suite de manière générale.

La prochaine fois nous nous attarderons sur l’équivalent pour le processus BPEL. Enfin cette série se terminera par la présentation d’un use case basé sur les audits : définir les performances des différentes étapes d’un composite !

Restez connecté !

Sources

Article Blog  A-Team Mediator