IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

scanner un fichier de log (eof) à la manière d'un tail


Sujet :

C++

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 91
    Par défaut scanner un fichier de log (eof) à la manière d'un tail
    Bonjour,

    je cherche à réaliser une fonction qui lit en continu un fichier de log à la manière d'un tail en C/C++. Le programme tourne sur Red Hat (RHEL5).
    Je dois ensuite extraire une chaîne de caractères dès qu'une certaine chaîne est trouvée. Je débute en C/C++, je développe cette application dans le cadre d'un stage.

    Pour le moment, je n'ai pas de solution mais des pistes :

    - system("tail -f -n 1 /chemin/log");
    - select()

    je n'ai pas de retour sur la commande system().

    J'ai regardé la fonction select() et je ne la comprends pâs encore très bien...

    Que pouvez-vous me conseillez pour mon affaire ?

  2. #2
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    C'est de la manipulation de fichier. Peut-être que la fonction popen aussi pourrait t'intéresser.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 91
    Par défaut
    je vous remercie pour la fonction popen

    j'ai bien récupéré le résultat d'une commande tail sauf que la sortie est en stdout. Or je souhaite récupérer le résultat de la commande popen dans une variable de type string.

    Voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    string tailCmd = "tail -f -n 1 /var/log/dhcdp.log";
    FILE *f; 
    char buffer[BUFSIZ];
     
    if ( (f = popen(tailCmd.c_str(), "r")) == NULL )  // ouverture
        fprintf(pxeLog, "%s", "5) Scan log dhcp OK \n");
    exit(1); 
     
    while ( fgets(buffer, BUFSIZ, f) != NULL ) 
            fputs(buffer, stdout);  //fonctionne dans le log sysout
            fputs(buffer, scan);  // ne fonctionne pas
    pclose(f); // fermeture

  4. #4
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Ton code est incomplet. Je ne peux pas voir d'où vient l'erreur.

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 91
    Par défaut
    j'ai extrait le code en cours de test. Le reste est insignifiant (un main() et un daemonloop() avec un while sans fin.

    Le programme est géré comme un service par un script /etc/init.d/ spécifique contenant les fonctions start-stop-restart.

    Je ne vois pas comment récupérer la valeur de retour de la commande popen dans une variable. Je souhaite ensuite filtrer la chaîne de caractère.

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 517
    Par défaut
    Le problème, autant que je sache, est que l'on ne peut pas utiliser select() pour être prévenu de l'insertion de caractères supplémentaires à la fin d'un fichier, car select() a surtout été prévu pour prévenir le processus de la possibilité d'action sur un descripteur de fichier. Autrement dit, la fonction surveille tous les appels potentiellement « bloquants » et rend la main dès que l'un d'eux ne l'est plus.

    Or, un fread() quelconque en fin de fichier a pour effet de rendre la main en positionnant le flag lu par feof(). En allant chercher les sources de « tail », on s'aperçoit que cette commande fait du polling, en vérifiant le contenu du fichier chaque seconde.

    C'est donc une lacune historique d'UNIX. Il faut donc se rabattre sur les mécanismes éventuels propres au système d'exploitation que tu utilises. Le noyau Linux en particulier propose inotify pour combler ces manques.

  7. #7
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Utiliser fseek et ftell, et ça marche facilement...

    Du style :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    int posstart, posend ;
     
    fichier = fopen...
    fseek (fichier, SEEND_END);
    posstart = ftell (...) ;
     
    while ( 1 )
    {
    fseek (fichier, SEEND_END);
    posend = ftell (..) ;
    ...
    for ( i = posstart ; i <= posend ; i++ )
     ...
     
    posstart = posend ;
    }

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 91
    Par défaut
    fseek et ftell me semblaient compliqués malgré le fait que j'ai compris leur utilisation.

    J'ai trouvé un exemple sur le forum, que j'ai adapté sur la fin :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     string getLastLine(string filename) {
     
    	#define _LL_BUFFSIZE_ 2048
    	string lastLine =""; // regardless, zero out our return string
    	char buff[_LL_BUFFSIZE_]; // our temporary input buffer
     
    	ifstream is; 
    	is.open(filename.c_str());
    	is.seekg (0, ios::end); // go to end of file
    	int length = is.tellg(); // find out how large it is
    	is.seekg(length-min(length,_LL_BUFFSIZE_),ios::beg); // seek back from end a short ways
    	// read in each line of the file until we're done
    	buff[0]=0;
    	is.getline(buff, _LL_BUFFSIZE_);
    	lastLine = buff;
    	is.close();
     
    	return lastLine;
    }
    utilisation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    string line = getLastLine(dhcpdLogPath);
    ce qui donne dans mon journal :

    3-6-2011 16:29:13 1) Ouverture du fichier de log
    3-6-2011 16:29:13 2) Changement du répertoire de travail OK.
    3-6-2011 16:29:13 3) Adresse MAC courante : 0
    3-6-2011 16:29:13 4) Le démon PXE démarre.
    3-6-2011 16:29:13 5) Lancement du scan journal isc-dhcp : /var/log/dhcpd.log
    3-6-2011 16:29:13 6) Extraction adresse MAC
    3-6-2011 16:29:13 May 26 15:42:09 xf11-00x dhcpd: Internet Systems Consortium DHCP Server V3.0.5-RedHat3-6-2011 16:39:48

  9. #9
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    d'une part c'est du C++ et pas du C, donc déjà normalement pas dans le bon forum...


    d'autre part, oui et ? est-ce que c'est ça que tu dois obtenir ? On n'a aucune idée si ce que tu nous donnes te satisfait ou non...

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 91
    Par défaut
    oui cela me convient. Mais je viens de me rendre compte que cela me renvoie toujours la même ligne qui n'est plus la dernière ligne du fichier mais qui l'était ... je cherche l'erreur je pense au buffer qui reste en mémoire système ... c'est bizarre

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 91
    Par défaut
    j'ai trouvé l'erreur :

    la fonction en l'état permet de mettre dans un tampon les charactères de la taille du tampon (2048) depuis la fin du fichier. j'ai ajouté un while sur le getline pour ajouter toutes les lignes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    string getLastLine(string filename) {
     
    	#define _LL_BUFFSIZE_ 200
     
    	string lastLine = ""; // initialisation à vide du résultat
    	char buff[_LL_BUFFSIZE_]; // initialisation du tampon
     
    	ifstream is;  // ouverture du flux - stream
    	is.open(filename.c_str()); // ouverture du fichier en argument de la fonction dans le flux
    	is.seekg (0, ios::end); // aller à la fin du fichier (EOF)
    	int length = is.tellg(); // trouver la taille du fichier
     
    	is.seekg(length-min(length,_LL_BUFFSIZE_),ios::beg); // déplacement du curseur à taille du tampon charactères de la fin du fichier
     
    	// lire les charactères jusqu'à la taille du buffer
    	buff[0]=0;
    	// ajouter tous les caractères, y compris si saut de ligne
    	while (is.getline(buff, _LL_BUFFSIZE_)) {
    		lastLine = buff;
    	}
    	is.close(); // fermeture du fichier et du flux
     
    	return lastLine; // retourner la dernière ligne du fichier
    }
    Par contre je ne suis pas totalement satisfait. Comment obtenir uniquement la dernière ligne d'un fichier de cette manière sachant que le nombre de caractère diffère entre chaque ligne vu que c'est un fichier de log ?

  12. #12
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par zelycorn Voir le message
    Comment obtenir uniquement la dernière ligne d'un fichier de cette manière sachant que le nombre de caractère diffère entre chaque ligne vu que c'est un fichier de log ?



    Si tu disais ça depuis le début, ça aurait été plus simple...

    tu te positionnes à la fin (fseek, SEEK_END), puis tu remontes de caractère en caractère pour chercher le premier '\n' ou '_r' (en général 10 = newline)..

    Ne pas oublier un saut de -2 une fois un caractère lu..

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 91
    Par défaut
    Merci pour cette proposition, je vais voir pour la mettre en place.

    J'ai également une autre (solution de départ 1) solution qui pourrait me convenir : utiliser popen. Je n'arrivais pas à récupérer le résultat auparavant. Désormais je sais le faire, popen me retorunait un buffer en char .. je sais le convertir en string ...

Discussions similaires

  1. [tomcat 5] [paramétrage] fichier de log System.out.println
    Par Aldo dans le forum Tomcat et TomEE
    Réponses: 2
    Dernier message: 22/02/2005, 15h41
  2. [Oracle 8i/Fichier de log] - fichier log pour analyse erreur
    Par shaun_the_sheep dans le forum Oracle
    Réponses: 4
    Dernier message: 25/01/2005, 20h06
  3. [Tomcat] Fichier de logs
    Par yolepro dans le forum Tomcat et TomEE
    Réponses: 4
    Dernier message: 22/03/2004, 17h20
  4. Fichiers de Log
    Par Mouse dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 10/05/2003, 19h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo