Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/version.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#

set (TK_UTIL_MAJOR_VERSION "6")
set (TK_UTIL_MINOR_VERSION "11")
set (TK_UTIL_MINOR_VERSION "12")
set (TK_UTIL_RELEASE_VERSION "0")
set (TK_UTIL_VERSION ${TK_UTIL_MAJOR_VERSION}.${TK_UTIL_MINOR_VERSION}.${TK_UTIL_RELEASE_VERSION})

Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ enable_testing ( )
add_subdirectory (TkUtil)
add_subdirectory (TkUtilScripting)
add_subdirectory (TkutilLauncher)
add_subdirectory (appstats)
add_subdirectory (tests)
add_subdirectory (encoding)
add_subdirectory (socket_proxy)
Expand Down
134 changes: 130 additions & 4 deletions src/TkUtil/ApplicationStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "TkUtil/ApplicationStats.h"
#include "TkUtil/Exception.h"
#include "TkUtil/File.h"
#include "TkUtil/NumericConversions.h"
#include "TkUtil/UTF8String.h"

#include <TkUtil/Date.h>
Expand All @@ -16,6 +17,7 @@
#include <sys/file.h> // flock
#include <stdio.h> // fopen, fseek, fscanf, fprintf
#include <string.h> // strerror
#include <sys/stat.h> // fchmod
#include <sys/types.h>
#include <unistd.h> // fork, setsid

Expand Down Expand Up @@ -49,6 +51,15 @@ ApplicationStats::~ApplicationStats ( )
} // ApplicationStats::~ApplicationStats


string ApplicationStats::getFileName (const string& appName, const string& logDir, size_t month, size_t year)
{
UTF8String fileName (Charset::UTF_8);
fileName << logDir << "/" << appName << "_" << NumericConversions::toStr (year, 4) << NumericConversions::toStr (month, 2) << ".logs";

return fileName.utf8 ( );
} // ApplicationStats::getFileName


void ApplicationStats::logUsage (const string& appName, const string& logDir)
{
// En vue de ne pas altérer le comportement de l'application tout est effectuée dans un processus fils.
Expand Down Expand Up @@ -81,11 +92,11 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir)
// Le nom du fichier :
const Date date;
const string user (UserData (true).getName ( ));
UTF8String fileName;
fileName << logDir << "/" << appName << "_" << IN_UTIL setw (4) << date.getYear ( ) << setw (2) << (unsigned long)date.getMonth ( ) << ".logs";
UTF8String fileName (getFileName (appName, logDir, (unsigned long)date.getMonth ( ), date.getYear ( )), Charset::UTF_8);

// On ouvre le fichier en lecture/écriture :
FILE* file = fopen (fileName.utf8 ( ).c_str ( ), "r+"); // Ne créé pas le fichier => on le créé ci-dessous si nécessaire :
FILE* file = fopen (fileName.utf8 ( ).c_str ( ), "r+"); // Ne créé pas le fichier => on le créé ci-dessous si nécessaire :
const bool created = NULL == file ? true : false;
file = NULL == file ? fopen (fileName.utf8 ( ).c_str ( ), "a+") : file;
if (NULL == file)
{
Expand Down Expand Up @@ -134,6 +145,18 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir)
fclose (file);
return;
} // if (0 != flock (fd, LOCK_EX))

// Conférer aufichier les droits en écriture pour tous le monde si il vient d'être créé :
if (true == created)
{
if (0 != fchmod (fd, S_IRWXU | S_IRWXG | S_IRWXO))
{
ConsoleOutput::cerr ( ) << "Erreur lors du confèrement à autrui des droits en écriture sur le fichier de logs " << fileName << " : " << strerror (errno) << co_endl;
fclose (file);
return;

} // if (0 != fchmod (fd, S_IRWXU | S_IRWXG | S_IRWXO))
} // if (true == created)

// Lecture et actualisation des logs existants :
map<string, size_t> logs;
Expand Down Expand Up @@ -200,8 +223,111 @@ void ApplicationStats::logUsage (const string& appName, const string& logDir)
{
ConsoleOutput::cerr ( ) << "Erreur lors du déverrouillage du fichier de logs " << fileName << " : " << strerror (errno) << co_endl;
fclose (file);
} // if (0 != flock (fd, LOCK_UN))
} // if (0 != flock (fd, LOCK_UN))

fclose (file);
file = NULL;
fd = -1;
} // ApplicationStats::logUsage


void ApplicationStats::logStats (std::ostream& output, const std::string& appName, const string& from, const string& to, const std::string& logDir)
{
map<string, size_t> logs;
const size_t fromMonth = NumericConversions::strToULong (UTF8String (from).substring (0, 1));
const size_t fromYear = NumericConversions::strToULong (UTF8String (from).substring (2));
const size_t toMonth = NumericConversions::strToULong (UTF8String (to).substring (0, 1));
const size_t toYear = NumericConversions::strToULong (UTF8String (to).substring (2));

if (fromYear == toYear)
{
for (size_t m = fromMonth; m <= toMonth; m++)
{
cout << "Performing " << m << "/" << fromYear << endl;
UTF8String fileName (getFileName (appName, logDir, m, fromYear), Charset::UTF_8);

if (0 != readLogs (fileName, logs))
ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " : " << strerror (errno) << co_endl;
} // for (size_t m = fromMonth; m <= toMonth; m++)
} // if (fromYear == toYear)
else
{
for (size_t m = fromMonth; m <= 12; m++)
{
cout << "Performing " << m << "/" << fromYear << endl;
UTF8String fileName (getFileName (appName, logDir, m, fromYear), Charset::UTF_8);

if (0 != readLogs (fileName, logs))
ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " : " << strerror (errno) << co_endl;
}
for (size_t y = fromYear + 1; y < toYear; y++)
for (size_t m = 1; m <= 12; m++)
{
cout << "Performing " << m << "/" << y << endl;
UTF8String fileName (getFileName (appName, logDir, m, y), Charset::UTF_8);

if (0 != readLogs (fileName, logs))
ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " : " << strerror (errno) << co_endl;
}
for (size_t m = 1; m <= toMonth; m++)
{
cout << "Performing " << m << "/" << toYear << endl;
UTF8String fileName (getFileName (appName, logDir, m, toYear), Charset::UTF_8);

if (0 != readLogs (fileName, logs))
ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " : " << strerror (errno) << co_endl;
}
} // else if (fromYear == toYear)

// On imprime les résultats dans le flux :
for (map<string, size_t>::const_iterator itl = logs.begin ( ); logs.end ( ) != itl; itl++)
output << (*itl).first << "\t\t" << (*itl).second << endl;
} // ApplicationStats::logStats


int ApplicationStats::readLogs (const string& fileName, map<string, size_t>& logs)
{
File logFile (fileName);
if (false == logFile.isReadable ( ))
return 0;

int retval = 0;
errno = 0;
FILE* file = fopen (fileName.c_str ( ), "r");
if (NULL != file)
{
retval = readLogs (*file, fileName, logs);
fclose (file);
} // if (NULL != file)

return retval;
} // ApplicationStats::readLogs


int ApplicationStats::readLogs (FILE& file, const string& fileName, map<string, size_t>& logs)
{
errno = 0;
size_t line = 1, count = 0;
int flag = 0;
char name [256];
while (2 == (flag = fscanf (&file, "%s\t%u", name, &count)))
{
line++;
map<string, size_t>::iterator itl = logs.find (name);
if (logs.end ( ) == itl)
logs.insert (pair<string, size_t> (name, count));
else
(*itl).second += count;
count = 0;
} // while (2 == fscanf (file, "%s\t%u", name, &count))
if ((flag < 2) && (EOF != flag))
{
ConsoleOutput::cerr ( ) << "Erreur lors de la lecture du fichier de logs " << fileName << " en ligne " << (unsigned long)line << " : fichier probablement corrompu." << co_endl;
return -1;
} // if (flag < 2)

return errno;
} // ApplicationStats::readLogs


END_NAMESPACE_UTIL
34 changes: 31 additions & 3 deletions src/TkUtil/public/TkUtil/ApplicationStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@

#include <TkUtil/util_config.h>

#include <map>
#include <string>

#include <stdio.h>


BEGIN_NAMESPACE_UTIL

Expand All @@ -27,20 +30,45 @@ class ApplicationStats
* utilisateur nbutilisations
*/
//@{ Fichier simplifié d'utilisation d'applications


/**
* @param appName est le nom de l'application
* @param logDir est le répertoire où sont stockés les fichiers de logs
* @param Mois et année concernés
* @return Un nom de fichier simplifié de logs.
*/
static std::string getFileName (const std::string& appName, const std::string& logDir, size_t month, size_t year);

/**
* Ajoute une utilisation de cette application à l'utilisateur courrant. L'opération se fait dans un processus détaché.
* Toute erreur rencontrée est affichée dans la console de lancement de l'application.
* @param appName est le nom de l'application
* @param logDir est le répertoire où sont stockés les fichiers de logs
*/
static void logUsage (const std::string& appName, const std::string& logDir);


/**
* Rassemble les utilisations d'une application sur la période demandée et en affiche la synthèse dans le flux transmis en argument.
* Toute erreur rencontrée est affichée dans la console de lancement de l'application.
* @param flux où est écrit la synthèse
* @param appName est le nom de l'application
* @param est la date de début au format MMYYYY
* @param est la date de fin au format MMYYYY
* @param logDir est le répertoire où sont stockés les fichiers de logs
*/
static void logStats (std::ostream& output, const std::string& appName, const std::string& logDir, const std::string& from, const std::string& to);
//@} Fichier simplifié d'utilisation d'applications


private :


/**
* Charge les logs du fichiers ouvert transmis en argument dans la map transmise en second argument.
* @return 0 en cas de succès. En cas d'erreur errno est positionné.
*/
static int readLogs (const std::string& fileName, std::map<std::string, size_t>& logs);
static int readLogs (FILE& file, const std::string& fileName, std::map<std::string, size_t>& logs);

/**
* Constructeurs/Destructeur : interdits.
*/
Expand Down
41 changes: 41 additions & 0 deletions src/appstats/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
set (CURRENT_PACKAGE_NAME "Appstats")

include (${CMAKE_SOURCE_DIR}/cmake/version.cmake)
include (${GUIToolkitsVariables_CMAKE_DIR}/common.cmake)
include (${GUIToolkitsVariables_CMAKE_DIR}/workarounds.cmake)

add_executable (appstats appstats.cpp)

target_link_libraries (appstats PUBLIC TkUtil)
# INSTALL_RPATH modifie le rpath pour les libs internes au projet :
set_target_properties (appstats PROPERTIES INSTALL_RPATH_USE_LINK_PATH 1 INSTALL_RPATH ${CMAKE_PACKAGE_RPATH_DIR})

# INSTALLATION :
include(CMakePackageConfigHelpers)
# ConfigPackageLocation : c'est plus ou moins standardisé, le défaut étant lib/cmake.
# On nos recommande très vivement d'utiliser ce répertoire afin de limiter les soucis par la suite,
# notamment au niveau des vues.
set (ConfigPackageLocation ${CMAKE_CMAKE_DIR})

install(TARGETS appstats EXPORT Appstats DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)

# Utilisation par d'autres modules de appstats :
set (RUNTIME_INSTALL_DIR bin/) # appstats_RUNTIME_DIR avec AppstatsConfig.cmake.in
configure_package_config_file(cmake/${CURRENT_PACKAGE_NAME}Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${CURRENT_PACKAGE_NAME}/${CURRENT_PACKAGE_NAME}Config.cmake
INSTALL_DESTINATION ${CMAKE_CMAKE_DIR}
PATH_VARS RUNTIME_INSTALL_DIR
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${CURRENT_PACKAGE_NAME}/${CURRENT_PACKAGE_NAME}ConfigVersion.cmake
VERSION ${TK_UTIL_VERSION}
COMPATIBILITY SameMinorVersion
)
install (
FILES
${CMAKE_CURRENT_BINARY_DIR}/${CURRENT_PACKAGE_NAME}/${CURRENT_PACKAGE_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${CURRENT_PACKAGE_NAME}/${CURRENT_PACKAGE_NAME}ConfigVersion.cmake
DESTINATION ${ConfigPackageLocation} PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE WORLD_READ
)


Loading