/* * * Copyright (c) 1999 - 2011 my-Channels Ltd * Copyright (c) 2012 - 2017 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors. * * Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG. * */ #include "nSampleApp.h" #include "ntop.h" #include "nSessionAttributes.h" #include "nRealmNode.h" #include "nThreadPool.h" #include "nConstants.h" #include "nSessionFactory.h" #include "Poco/Thread.h" #include #include using namespace com::pcbsys::nirvana::client; using namespace com::pcbsys::nirvana::nAdminAPI; using namespace com::pcbsys::nirvana::nAdminAPI::apps; ntop* ntop::m_pMyself = NULL; ntop::ntop() : m_pNode(NULL), m_option('l'), m_totConsumed(-1), m_totPublished(0), m_refreshRate(2000), m_rname("nsp://localhost:9000"), m_totMem(0), m_freeMem(-1), m_curCons(-1), m_prevTime(0) { } /// /// * This function creates a session based on RNAME and establishes the nRealmNode for that realm /// void ntop::getRealmNode() { try { printf("Establishing realm node..."); nSessionAttributes *pNsa = new nSessionAttributes(m_rname); nRealmNode *pNode = new nRealmNode(pNsa); if (!pNode->isAuthorised()) { printf("User not authorised on this node\n"); exit(1); } printf("done\n\n"); m_pNode = pNode; } catch (Exception e) { exit(1); } } /// /// * The Vector of thread pool details for the realm /// std::list* ntop::getThreadPools() { return m_pNode->getThreadPoolDetails(); } /// /// * This method takes a vector of thread pool and prints out information from each in a table /// * /// * A vector of thread pools /// void ntop::printThreadPools(std::list& threadPools) { printf("\n\n\n\n\n\n"); //The names of the thread pools vary in size, to longest name is 23 characters. In case other names are //added at a later date, this length variable can be adjusted int nameLength = 25; printf("Name"); //this function is used to print multiple spaces at a time for alignment purposes printSpaces(nameLength - 4); printf("Idle Allocated Queued Tasks\n"); printSpaces(nameLength); printf("Threads Threads Tasks Executed\n\n"); for (std::list::iterator iterator = threadPools.begin(); iterator != threadPools.end(); iterator++) { nThreadPool *pThread = *iterator; int idle = pThread->getIdle(); std::string name = pThread->getName(); int queue = pThread->getQueue(); int size = pThread->getSize(); longlong total = pThread->getTotal(); printf("%s ", name.c_str()); printSpaces(nameLength - name.length()); printf("%d\t %d\t %d\t %lld\n", idle, size, queue, total); } } /// /// * The class nTop implements nLogListener. By adding this class as a listener of the rNode, whenever a new /// * log entry is added to the rNode, the report method is called which prints out the log. /// void ntop::getLog() { m_pNode->addLogListener(this); } /// /// * This method is called when a new log entry is added to the realm /// * The log entry /// void ntop::report(const std::string& rep) { printf("%s\n", rep.c_str()); } /// /// * Prints information on the events in the realm /// void ntop::printEventsTable() { printf("\n\n\n\n\n\n"); longlong conPerSec = 0; longlong pubPerSec = 0; /// /// * if totConsumed is -1 then it means this is the first iteration of calculating the subscribers and consumers /// * therefore it is not possible to calculate the rate at which consumers and subscribers are increasing/decreasing /// if (m_totConsumed != -1) { longlong timeChange = nConstants::currentTimeMillis() - m_prevTime; conPerSec = (m_pNode->getTotalSubscribed() - m_totConsumed); if(conPerSec > 0) { conPerSec /= (timeChange / 1000); } pubPerSec = (m_pNode->getTotalPublished() - m_totPublished); if(pubPerSec > 0) { pubPerSec /= (timeChange / 1000); } } m_prevTime = nConstants::currentTimeMillis(); m_totConsumed = m_pNode->getTotalSubscribed(); m_totPublished = m_pNode->getTotalPublished(); printf("~~~~~~~~Event Status~~~~~~~\n\n"); printf("Consumed - %lld\n\n", m_totConsumed); printf("Published - %lld\n\n", m_totPublished); printf("Consumed/sec - %lld\n\n", conPerSec); printf("Published/sec - %lld\n\n", pubPerSec); printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"); } /// /// * This method resets variables back to there initial values each time the option variable is changed. This is /// * necessary so that for example the consumed/sec rate is not calculated based on previous values. /// void ntop::reset() { m_totConsumed = -1; m_totPublished = -1; m_freeMem = -1; m_curCons = -1; //try to remove the logListener. A log listener may not have been added however so must catch exception if it //has not. try { m_pNode->delLogListener(this); } catch (Exception e) { } } /// /// * This method prints the details of memory usage /// void ntop::printMemoryUsage() { printf("\n\n\n\n\n\n"); longlong change = 0; if (m_freeMem != -1) { if ((change = m_pNode->getFreeMemory() - m_freeMem) < 0) { change = m_freeMem - m_pNode->getFreeMemory(); } } m_freeMem = m_pNode->getFreeMemory(); longlong usedMem = m_totMem - m_freeMem; /// /// * dividing by (1024*1024) gives the values in terms of mega bytes /// printf("~~Memory Usage (M)~~\n\n"); #ifdef WIN32 printf("Total - %I64d\n", (m_totMem / (1024 * 1024))); printf("Free - %I64d\n", (m_freeMem / (1024 * 1024))); printf("Used - %I64d\n", (usedMem / (1024 * 1024))); printf("Change - %I64d\n", (change / (1024 * 1024))); #else printf("Total - %lld\n", (m_totMem / (1024 * 1024))); printf("Free - %lld\n", (m_freeMem / (1024 * 1024))); printf("Used - %lld\n", (usedMem / (1024 * 1024))); printf("Change - %lld\n", (change / (1024 * 1024))); #endif printf("~~~~~~~~~~~~~~~~~~~~\n\n"); } /// /// * Prints details of connections to the realm. /// void ntop::printConnectionStatus() { printf("\n\n\n\n\n\n"); longlong totCons = m_pNode->getTotalConnections(); double rate = 0; if (m_curCons != -1) { longlong timeChange = nConstants::currentTimeMillis() - m_prevTime; //must cast to double otherwise the result of 3/2 = 1 rather than 1.5 rate = (double)(m_pNode->getCurrentConnections() - m_curCons) / (double)(timeChange / 1000); } m_curCons = m_pNode->getCurrentConnections(); m_prevTime = nConstants::currentTimeMillis(); printf("~~Connection Status~~\n\n"); printf("Total - %lld\n", totCons); printf("Current - %d\n", m_curCons); printf("Rate - %f\n", rate); printf("~~~~~~~~~~~~~~~~~~~~~\n\n"); } /// /// * In order to align the tables being printed, it is often necessary to print out multiple spaces based on the length /// * of a name for example. /// * The number of spaces to be printed. /// void ntop::printSpaces(int length) { for (int i = 0; i < length; i++) { printf(" "); } } /// /// * This method gives details of how to use the program. It describes what information is displayed when certain keys /// * are pressed. /// void ntop::helpMessage() { printf("~~~~~~~~~~~~~~~~~~~~~~~~~~Help~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"); printf(" nTop [refreshRate] \n\n"); printf("In order to view different Information, press one of the\n"); printf("character keys specified below\n"); char plural = ' '; if (m_refreshRate != 1000) { plural = 's'; } printf("All information is updated every %d second%c. Once you\n", (m_refreshRate / 1000), plural); printf("have chosen an option and the information is displayed,\n"); printf("simply press another character key to change the\n"); printf("information shown.\n\n"); printf("t : realm thread pools\n"); printf("e : event status\n"); printf("m : memory usage\n"); printf("c : connection status\n"); printf("l : log file\n"); printf("h : show this help message\n"); printf("q : exit the system\n\n"); printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"); } /// /// * Initially prints the help message to show the user the options available then reads the option from the input /// * and start a thread to display the required information. The method then monitors the keyboard for key presses /// * and updates the option variable depending on the input character. /// void ntop::doit() { helpMessage(); std::string line; std::getline(std::cin, line); if (line != "q") { try { m_option = line[0]; } catch (Exception read) { exit(1); } } Thread *pScreenWriter = new Thread("Screen writer"); pScreenWriter->setPriority (Poco::Thread::PRIO_LOW); pScreenWriter->start(*this); while (true) { try { std::getline(std::cin, line); if (line[0] != 'q') { reset(); m_option = line[0]; /// /// * The information will refresh every refreshRate milliseconds however, if the user requests to see new /// * information, then they should not have to wait refreshRate milliseconds for the new information to appear. /// * To solve this, rather than the thread sleeping, it waits for a maximum of refreshrate milliseconds and /// * then continues. If within this time the option is changed, we notify the thread here and it immediately /// * continues /// m_change.lock(); m_change.notify(); m_change.unlock(); } else { break; } } catch (Exception read) { exit(1); } } } /// /// * When a new thread is started, this method is called. The thread displays information depending on the character /// * in the option variable. /// void ntop::run() { while (true) { switch (m_option) { case 't': { std::list *pThreadPools = getThreadPools(); printThreadPools(*pThreadPools); delete pThreadPools; break; } case 'e': { printEventsTable(); break; } //The logListener will print to the screen everytime a new log report is received. Therefore it is not //necessary to continue looping calling getLog() hence the option is set to X case 'l': { getLog(); m_option = 'X'; break; } case 'm': { printMemoryUsage(); break; } case 'c': { printConnectionStatus(); break; } case 'h': { helpMessage(); //The help message will not update so only needs to be printed once hence the option variable is changed to X. m_option = 'X'; break; } case 'q': { printf("System exiting\n"); exit(0); break; } //This case can only be reached if the code sets option to X. If the user enters X into the terminal, //it will be converted to lower case. This means the X case can be used whenever //you want to print something only once rather than in the loop but you want the loop to continue. case 'X': { break; } default: { helpMessage(); m_option = 'X'; break; } } /// /// * the thread waits for a maximum of refreshRate milliseconds then continues (loops again and refreshes the /// * information). The thread may continue before this time is up if it received notification. /// m_change.lock(); try { m_change.unlock(); m_change.tryWait (m_refreshRate); m_change.lock(); } catch (Exception ie) { } m_change.unlock(); } } void ntop::usage() { printf("Usage...\n\n"); printf("nTop [refreshRate]\n"); printf(" - the rname of the server to connect to\n"); printf("[refreshRate] - the rate at which the information is reloaded on screen (milliseconds) \n\n"); } void ntop::main (int argc, char** argv) { m_pMyself = new ntop (); if (argc <= 2) { usage(); exit(1); } if ((argc == 3)) { try { m_pMyself->m_rname = argv[1]; m_pMyself->m_refreshRate = atoi(argv[2]); } catch (Exception e) { //If the paramater entered is not a numerical value the usage will be printed out usage(); exit(1); } } //this function establishes a realm node and assigns it to global variable called rNode m_pMyself->getRealmNode(); //update total memory as this value is constant m_pMyself->m_totMem = m_pMyself->m_pNode->getTotalMemory(); m_pMyself->doit(); try { m_pMyself->m_pNode->close(); } catch (Exception e) { } //Close any other sessions within this JVM so that we can exit nSessionFactory::shutdown(); } int main (int argc, char** argv) { ntop* pMain = new ntop(); pMain->main (argc, argv); return 0; }