1022 lines
39 KiB
C++
1022 lines
39 KiB
C++
|
|
#include "crapview.h"
|
|
|
|
#include "utilities/printables.h"
|
|
#include "utilities/strings.h"
|
|
|
|
#include <QGraphicsItem>
|
|
#include <QTableWidget>
|
|
|
|
|
|
const int& Crapview::getDialogsLevel() const
|
|
{
|
|
return this->dialogs_level;
|
|
}
|
|
void Crapview::setDialogsLevel( const int new_level )
|
|
{
|
|
this->dialogs_level = new_level;
|
|
}
|
|
|
|
|
|
void Crapview::setDbPath( const std::string& path )
|
|
{
|
|
this->dbQuery.setDbPath( path + "/collection.db" );
|
|
}
|
|
|
|
|
|
const QString Crapview::parseBooleanFilter( const QString& filter_str ) const
|
|
{
|
|
QString aux{ filter_str };
|
|
aux = aux.replace( "NOT TRUE", "!= 1", Qt::CaseSensitivity::CaseInsensitive );
|
|
aux = aux.replace( "NOT FALSE", "!= 0", Qt::CaseSensitivity::CaseInsensitive );
|
|
aux = aux.replace( "TRUE", "1", Qt::CaseSensitivity::CaseInsensitive );
|
|
aux = aux.replace( "FALSE", "0", Qt::CaseSensitivity::CaseInsensitive );
|
|
return this->parseNumericFilter( aux );
|
|
}
|
|
|
|
|
|
const QString Crapview::parseNumericFilter( const QString& filter_str ) const
|
|
{
|
|
QString final_str;
|
|
if ( ! filter_str.isEmpty() ) {
|
|
QString aux_{ this->parseTextualFilter( filter_str ) };
|
|
if ( aux_ == "NULL" || aux_ == "NOT NULL" ) {
|
|
final_str = aux_;
|
|
} else {
|
|
std::vector<std::string> f_list;
|
|
StringOps::splitrip( f_list, filter_str.toStdString(), ' ' );
|
|
if ( ! f_list.empty() ) {
|
|
std::string& aux{ f_list.at(0) };
|
|
if ( StringOps::isNumeric( aux ) ) {
|
|
// no symbol specified, set '=' as default
|
|
final_str += "=";
|
|
final_str += QString::fromStdString( aux );
|
|
} else {
|
|
if ( StringOps::isNumeric( StringOps::lstrip( aux, "!<=>" ) ) ) {
|
|
// symbol/value
|
|
final_str += QString::fromStdString( aux ).replace("==","=");
|
|
} else if ( StringOps::lstrip( aux, "!<=>" ).empty() ) {
|
|
// symbol at first, maybe a value follows
|
|
if ( f_list.size() > 1 ) {
|
|
final_str += QString::fromStdString( aux ).replace("==","=");
|
|
const size_t ck = final_str.size();
|
|
const size_t max = f_list.size();
|
|
for ( size_t i{1}; i<max; i++ ) {
|
|
aux = f_list.at( i );
|
|
if ( StringOps::isNumeric( aux ) ) {
|
|
final_str += QString::fromStdString( aux );
|
|
break;
|
|
}
|
|
}
|
|
if ( final_str.size() == ck ) {
|
|
final_str = "";
|
|
}
|
|
}
|
|
|
|
}/* else {
|
|
// skip
|
|
}*/
|
|
}
|
|
}
|
|
f_list.clear();
|
|
}
|
|
}
|
|
return final_str.replace("==","=");
|
|
}
|
|
|
|
|
|
const QString Crapview::parseTextualFilter( const QString& filter_str ) const
|
|
{
|
|
QString aux{ filter_str };
|
|
if ( ! filter_str.isEmpty() ) {
|
|
const std::string str{ StringOps::strip( filter_str.toUpper().toStdString() ) };
|
|
if ( str == "NULL" ) {
|
|
aux = "NULL";
|
|
} else if ( str == "NOT NULL" || str == "*" ) {
|
|
aux = "NOT NULL";
|
|
}
|
|
}
|
|
return aux;
|
|
}
|
|
|
|
|
|
|
|
const QString Crapview::getLogFieldString ( const int field_id ) const
|
|
{
|
|
return TR::tr( this->dbQuery.FIELDS.at( field_id ).c_str() );
|
|
}
|
|
|
|
const int Crapview::getLogFieldID ( const QString& field_str ) const
|
|
{
|
|
int f{ 0 };
|
|
for ( const auto& [id,str] : this->dbQuery.FIELDS ) {
|
|
if ( TR::tr(str.c_str()) == field_str ) {
|
|
f = id;
|
|
break;
|
|
}
|
|
}
|
|
return f;
|
|
}
|
|
|
|
|
|
const int Crapview::getMonthNumber( const QString& month_str ) const
|
|
{
|
|
int m{ 0 };
|
|
for ( const auto& [num,str] : this->dbQuery.MONTHS ) {
|
|
if ( TR::tr(str.c_str()) == month_str ) {
|
|
m = num;
|
|
break;
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
|
|
void Crapview::refreshDates()
|
|
{
|
|
Result<stats_dates_t> result;
|
|
this->dbQuery.refreshDates( result );
|
|
if ( result ) {
|
|
this->dates.clear();
|
|
// std::unordered_map<int, std::unordered_map<int, std::unordered_map<int, std::vector<int>>>>
|
|
// { web_server_id : { year : { month : [ days ] } } }
|
|
this->dates = std::move( result.getData() );
|
|
}
|
|
}
|
|
void Crapview::clearDates()
|
|
{
|
|
this->dates.clear();
|
|
}
|
|
|
|
const QStringList Crapview::getYears( const QString& web_server ) const
|
|
{
|
|
QStringList years;
|
|
if ( ! this->dates.empty() ) {
|
|
const int ws{ this->WebServer_s2i.value( web_server ) };
|
|
if ( ! this->dates.at( ws ).empty() ) {
|
|
const auto& y{ this->dates.at( ws ) };
|
|
std::transform( y.cbegin(), y.cend(),
|
|
std::back_inserter( years ),
|
|
[](const auto& p){ return QString::number( p.first ); } );
|
|
}
|
|
}
|
|
return years;
|
|
}
|
|
const QStringList Crapview::getMonths( const QString& web_server, const QString& year ) const
|
|
{
|
|
QStringList months;
|
|
if ( ! this->dates.empty() ) {
|
|
const int ws{ this->WebServer_s2i.value( web_server ) };
|
|
if ( ! this->dates.at( ws ).empty() ) {
|
|
const int y{ year.toInt() };
|
|
if ( ! this->dates.at( ws ).at( y ).empty() ) {
|
|
const auto& m{ this->dates.at( ws ).at( y ) };
|
|
const auto& m_tr{ this->dbQuery.MONTHS };
|
|
std::transform( m.cbegin(), m.cend(),
|
|
std::back_inserter( months ),
|
|
[&m_tr](const auto& p){ return TR::tr(m_tr.at( p.first ).c_str()); } );
|
|
}
|
|
}
|
|
}
|
|
return months;
|
|
}
|
|
const QStringList Crapview::getDays( const QString& web_server, const QString& year, const QString& month ) const
|
|
{
|
|
QStringList days;
|
|
if ( ! this->dates.empty() ) {
|
|
const int ws{ this->WebServer_s2i.value( web_server ) };
|
|
if ( ! this->dates.at( ws ).empty() ) {
|
|
const int y{ year.toInt() };
|
|
if ( ! this->dates.at( ws ).at( y ).empty() ) {
|
|
const int m{ this->getMonthNumber( month ) };
|
|
if ( ! this->dates.at( ws ).at( y ).at( m ).empty() ) {
|
|
const auto& d{ this->dates.at( ws ).at( y ).at( m ) };
|
|
std::transform( d.cbegin(), d.cend(),
|
|
std::back_inserter( days ),
|
|
[](const int day){ return QString::number( day ); } );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return days;
|
|
}
|
|
const QStringList Crapview::getHours() const
|
|
{
|
|
return QStringList{"00","01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23"};
|
|
}
|
|
|
|
const QStringList Crapview::getFields( const std::string& tab ) const
|
|
{
|
|
QStringList list;
|
|
const auto& f{ this->fields.at( tab ) };
|
|
std::transform( f.cbegin(), f.cend(),
|
|
std::back_inserter( list ),
|
|
[](const auto& field){ return TR::tr( field.c_str() ); } );
|
|
return list;
|
|
}
|
|
|
|
|
|
////////////////
|
|
//// CHARTS ////
|
|
////////////////
|
|
void Crapview::sliceClicked( QtCharts::QPieSlice* slice )
|
|
{
|
|
slice->setExploded( !slice->isExploded() );
|
|
slice->setLabelVisible( !slice->isLabelVisible() );
|
|
}
|
|
|
|
|
|
void Crapview::updateWarn( QTableWidget* table , const QString& web_server ) const
|
|
{
|
|
std::vector<std::tuple<int, int>> updates; // { (rowid, warn) }
|
|
for ( int i{0}; i<table->rowCount(); i++ ) {
|
|
QTableWidgetItem* item = table->item( i, 0 );
|
|
if ( item->checkState() == Qt::CheckState::Checked && item->text() == TR::tr( BOOLS__FALSE.c_str() ) ) {
|
|
// remove warning
|
|
updates.push_back( std::make_tuple( table->item( i, table->columnCount()-1 )->text().toInt(), 1 ) );
|
|
} else if (item->checkState() == Qt::CheckState::Unchecked && item->text() == TR::tr( BOOLS__TRUE.c_str() ) ) {
|
|
// add warning
|
|
updates.push_back( std::make_tuple( table->item( i, table->columnCount()-1 )->text().toInt(), 0 ) );
|
|
}
|
|
}
|
|
this->dbQuery.updateWarnings( web_server, updates );
|
|
}
|
|
|
|
void Crapview::drawWarn( QTableWidget* table, QtCharts::QChartView* chart, const QChart::ChartTheme& theme, const QString& web_server, const QString& year, const QString& month, const QString& day, const QString& hour ) const
|
|
{
|
|
Result<stats_warn_items_t> result;
|
|
this->dbQuery.getWarnCounts(
|
|
result,
|
|
web_server,
|
|
year, month, day, hour );
|
|
if ( result ) {
|
|
// std::vector<std::vector<std::vector<std::vector<QString>>>>
|
|
// day -> [ hours[ 10th_minutes[ lines[ log_data ] ] ] ]
|
|
// hour -> [ 10th_minutes[ minute[ lines[ log_data ] ] ] ]
|
|
auto& items = result.getData();
|
|
|
|
// bars
|
|
std::vector<std::vector<QBarSet*>> sets;
|
|
|
|
// build the bars and the table upon data
|
|
QString date;
|
|
QColor warn_col{ 255, 140, 0, 255 };
|
|
int norm_count, warn_count, sum_count, max_count=0, n_rows=0;
|
|
if ( hour.isEmpty() ) {
|
|
// entire day
|
|
for ( int i{0}; i<6; i++ ) {
|
|
sets.push_back( std::vector<QBarSet*>() );
|
|
sets.back().push_back( new QBarSet("") );
|
|
sets.back().push_back( new QBarSet("") );
|
|
}
|
|
for ( size_t h{0}; h<24ul; h++ ) {
|
|
for ( size_t m{0}; m<6ul; m++ ) {
|
|
const auto& data{ items.at( h ).at( m ) };
|
|
norm_count = warn_count = 0;
|
|
for ( const std::vector<QString>& line : data ) {
|
|
table->insertRow( n_rows );
|
|
table->setItem( n_rows, 0, new QTableWidgetItem( PrintSec::printableBool( line.at( 0 ).toInt() )));
|
|
if ( line.at( 0 ).toInt() != 0 ) {
|
|
table->item( n_rows, 0 )->setForeground( warn_col );
|
|
table->item( n_rows, 0 )->setCheckState( Qt::CheckState::Checked );
|
|
} else {
|
|
table->item( n_rows, 0 )->setCheckState( Qt::CheckState::Unchecked );
|
|
}
|
|
table->setItem( n_rows, 1, new QTableWidgetItem( PrintSec::printableDate( line.at( 1 ).toInt(), line.at( 2 ).toInt(), line.at( 3 ).toInt() )));
|
|
table->setItem( n_rows, 2, new QTableWidgetItem( PrintSec::printableTime( line.at( 4 ).toInt(), line.at( 5 ).toInt(), line.at( 6 ).toInt() )));
|
|
int col{ 3 };
|
|
const size_t max{ line.size() };
|
|
for ( size_t i{7}; i<max; i++ ) {
|
|
QTableWidgetItem* itm;
|
|
if ( (col == 7 || col >= 12) && !line.at(i).isEmpty() ) {
|
|
itm = new QTableWidgetItem();
|
|
itm->setData( Qt::DisplayRole, line.at( i ).toInt() );
|
|
} else {
|
|
itm = new QTableWidgetItem( line.at( i ) );
|
|
}
|
|
table->setItem( n_rows, col, itm );
|
|
col ++;
|
|
}
|
|
if ( line.at( 0 ) == "0" ) {
|
|
norm_count ++;
|
|
} else {
|
|
warn_count ++;
|
|
}
|
|
n_rows ++;
|
|
}
|
|
sets.at( m ).at( 0 )->append( norm_count );
|
|
sets.at( m ).at( 1 )->append( warn_count );
|
|
sum_count = norm_count + warn_count;
|
|
if ( sum_count > max_count ) {
|
|
max_count = sum_count;
|
|
}
|
|
}
|
|
}
|
|
date = PrintSec::printableDate( year, this->getMonthNumber( month ), day );
|
|
} else {
|
|
// 1 hour
|
|
for ( int i{0}; i<10; i++ ) {
|
|
sets.push_back( std::vector<QBarSet*>() );
|
|
sets.back().push_back( new QBarSet("") );
|
|
sets.back().push_back( new QBarSet("") );
|
|
}
|
|
for ( size_t g{0}; g<6ul; g++ ) {
|
|
for ( size_t m{0}; m<10ul; m++ ) {
|
|
const auto& data{ items.at( g ).at( m ) };
|
|
norm_count = warn_count = 0;
|
|
for ( const std::vector<QString>& line : data ) {
|
|
n_rows = table->rowCount();
|
|
table->insertRow( n_rows );
|
|
table->setItem( n_rows, 0, new QTableWidgetItem( PrintSec::printableBool( line.at( 0 ).toInt() )));
|
|
if ( line.at( 0 ).toInt() != 0 ) {
|
|
table->item( n_rows, 0 )->setForeground( warn_col );
|
|
table->item( n_rows, 0 )->setCheckState( Qt::CheckState::Checked );
|
|
} else {
|
|
table->item( n_rows, 0 )->setCheckState( Qt::CheckState::Unchecked );
|
|
}
|
|
table->setItem( n_rows, 1, new QTableWidgetItem( PrintSec::printableDate( line.at( 1 ).toInt(), line.at( 2 ).toInt(), line.at( 3 ).toInt() )));
|
|
table->setItem( n_rows, 2, new QTableWidgetItem( PrintSec::printableTime( line.at( 4 ).toInt(), line.at( 5 ).toInt(), line.at( 6 ).toInt() )));
|
|
for ( int i=7; i<line.size(); i++ ) {
|
|
table->setItem( n_rows, i-4, new QTableWidgetItem( line.at( i ) ));
|
|
}
|
|
if ( line.at( 0 ) == "0" ) {
|
|
norm_count ++;
|
|
} else {
|
|
warn_count ++;
|
|
}
|
|
}
|
|
sets.at( m ).at( 0 )->append( norm_count );
|
|
sets.at( m ).at( 1 )->append( warn_count );
|
|
sum_count = norm_count + warn_count;
|
|
if ( sum_count > max_count ) {
|
|
max_count = sum_count;
|
|
}
|
|
}
|
|
}
|
|
date = PrintSec::printableDate( year, this->getMonthNumber( month ), day ) + ", h " + hour;
|
|
}
|
|
table->verticalHeader()->setVisible( false );
|
|
|
|
// apply the colors and append to the series
|
|
QColor cols[]{ QColor(127,127,127), QColor(237,80,61) };
|
|
//QColor cols[] = {QColor(18,175,194), QColor(237,80,61)};
|
|
std::vector<QStackedBarSeries*> b_series;
|
|
const size_t max{ sets.size() };
|
|
for ( size_t i{0}; i<max; i++ ) {
|
|
const auto& set{ sets.at( i ) };
|
|
b_series.push_back( new QStackedBarSeries() );
|
|
for ( size_t w{0}; w<2ul; w++ ) {
|
|
QBarSet* b = set.at( w );
|
|
b->setColor( cols[ w ] );
|
|
b_series.at( i )->append( b );
|
|
}
|
|
}
|
|
for ( auto *s : b_series ) {
|
|
s->setBarWidth( 1 );
|
|
}
|
|
|
|
// set-up the bars chart
|
|
QChart* b_chart{ new QChart() };
|
|
// apply the theme
|
|
b_chart->setTheme( theme );
|
|
// append the bars
|
|
foreach ( auto& bars, b_series ) {
|
|
b_chart->addSeries( bars );
|
|
}
|
|
b_chart->setTitle( TR::tr( "Log Lines Marked as Warning" ) );
|
|
b_chart->legend()->setVisible( false );
|
|
/*b_chart->legend()->setAlignment( Qt::AlignBottom );
|
|
b_chart->setAnimationOptions( QChart::SeriesAnimations );*/
|
|
|
|
// craft the X-axis labels
|
|
QStringList categories;
|
|
if ( hour.isEmpty() ) {
|
|
categories << "00" << "01" << "02" << "03" << "04" << "05" << "06" << "07" << "08" << "09" << "10" << "11"
|
|
<< "12" << "13" << "14" << "15" << "16" << "17" << "18" << "19" << "20" << "21" << "22" << "23";
|
|
} else {
|
|
categories << "00" << "10" << "20" << "30" << "40" << "50";
|
|
}
|
|
|
|
// set-up the time-of-day axis (X)
|
|
QBarCategoryAxis* axisX{ new QBarCategoryAxis() };
|
|
axisX->append( categories );
|
|
axisX->setTitleText( date );
|
|
b_chart->addAxis( axisX, Qt::AlignBottom );
|
|
for ( auto* s : b_series ) {
|
|
s->attachAxis( axisX );
|
|
}
|
|
|
|
// set-up the count values axis (Y)
|
|
QValueAxis* axisY{ new QValueAxis() };
|
|
axisY->setLabelFormat( "%d" );
|
|
axisY->setTickCount( ( max_count < 8 ) ? max_count : 8 );
|
|
axisY->setRange( 0, max_count );
|
|
b_chart->addAxis( axisY, Qt::AlignLeft );
|
|
for ( auto* s : b_series ) {
|
|
s->attachAxis( axisY );
|
|
}
|
|
|
|
// apply the chart to the view
|
|
chart->setChart( b_chart );
|
|
chart->setRenderHint( QPainter::Antialiasing );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Crapview::drawSpeed( QTableWidget* table, QtCharts::QChartView* chart, const QChart::ChartTheme& theme, const QString& web_server, const QString& year, const QString& month, const QString& day, const QString& protocol, const QString& method, const QString& uri, const QString& query, const QString& response ) const
|
|
{
|
|
Result<stats_speed_items_t> result;
|
|
this->dbQuery.getSpeedData(
|
|
result,
|
|
web_server,
|
|
year, month, day,
|
|
protocol, method, uri, query, response );
|
|
if ( result ) {
|
|
// std::vector<std::tuple<long long, std::vector<QString>>>
|
|
// [ ( epoch_msec, [ log_data ] ) ]
|
|
auto& items{ result.getData() };
|
|
|
|
// draw the speed chart
|
|
QLineSeries* line{ new QLineSeries() };
|
|
|
|
// build the line upon data
|
|
size_t i{ 0 };
|
|
const size_t max_i{ items.size() };
|
|
int value{0}, aux_value, max_value{0}, n_rows{0};
|
|
long long time /* xD */, aux_time, count{1};
|
|
time = std::get<0>(items.at(0));
|
|
QDateTime dt;
|
|
std::vector<QString> data;
|
|
for ( const auto& item : items ) {
|
|
i++;
|
|
// append a value to the chart
|
|
aux_time = std::get<0>(item);
|
|
data = std::get<1>(item);
|
|
aux_value = data.at( 0 ).toInt();
|
|
// append only if the second is different, else sum
|
|
if ( aux_time > time ) {
|
|
value = value/count;
|
|
line->append( time, value );
|
|
if ( value > max_value ) {
|
|
max_value = value;
|
|
}
|
|
time = aux_time;
|
|
value = aux_value;
|
|
count = 1;
|
|
if ( i == max_i ) {
|
|
// final
|
|
line->append( time, value );
|
|
if ( value > max_value ) {
|
|
max_value = value;
|
|
}
|
|
}
|
|
} else {
|
|
count ++;
|
|
value += aux_value;
|
|
if ( i == max_i ) {
|
|
// final
|
|
value = value/count;
|
|
line->append( aux_time, value );
|
|
if ( value > max_value ) {
|
|
max_value = value;
|
|
}
|
|
}
|
|
}
|
|
// fill the teble with data
|
|
if ( !data.at(0).isEmpty() || !data.at(1).isEmpty() || !data.at(2).isEmpty() || !data.at(3).isEmpty() || !data.at(4).isEmpty() || !data.at(5).isEmpty() ) {
|
|
table->insertRow( n_rows );
|
|
auto* tt{ new QTableWidgetItem() };
|
|
tt->setData( Qt::DisplayRole, aux_value );
|
|
table->setItem( n_rows, 0, tt );
|
|
table->setItem( n_rows, 1, new QTableWidgetItem( data.at(1) ));
|
|
table->setItem( n_rows, 2, new QTableWidgetItem( data.at(2) ));
|
|
table->setItem( n_rows, 3, new QTableWidgetItem( data.at(3) ));
|
|
table->setItem( n_rows, 4, new QTableWidgetItem( data.at(4) ));
|
|
table->setItem( n_rows, 5, new QTableWidgetItem( data.at(5) ));
|
|
dt = QDateTime::fromMSecsSinceEpoch( aux_time );
|
|
table->setItem( n_rows, 6, new QTableWidgetItem( dt.time().toString("hh:mm:ss") ));
|
|
n_rows ++;
|
|
}
|
|
}
|
|
table->verticalHeader()->setVisible( false );
|
|
|
|
// fictitious line
|
|
QLineSeries* line_{ new QLineSeries() };
|
|
|
|
// color the area
|
|
QColor col1{ Qt::GlobalColor::red },
|
|
col2{ Qt::GlobalColor::green },
|
|
col3{ Qt::GlobalColor::blue };
|
|
//area->setColor( col );
|
|
QLinearGradient gradient{ QPointF(0, 0), QPointF(0, 1) };
|
|
gradient.setColorAt(0.3, col1.lighter( 90 ) );
|
|
gradient.setColorAt(0.7, col2.lighter( 90 ) );
|
|
gradient.setColorAt(1.0, col3.lighter( 90 ) );
|
|
gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
|
|
|
|
QPen pen{ line->pen() };
|
|
pen.setBrush( gradient );
|
|
pen.setWidth( 1 );
|
|
line->setPen(pen);
|
|
|
|
pen = line_->pen();
|
|
pen.setBrush( gradient );
|
|
pen.setWidth( 1 );
|
|
line_->setPen(pen);
|
|
|
|
// build the chart
|
|
QChart* l_chart{ new QChart() };
|
|
l_chart->setTheme( theme );
|
|
l_chart->addSeries( line );
|
|
l_chart->addSeries( line_ );
|
|
l_chart->setTitle( TR::tr( "Time Taken to Serve Requests" ) );
|
|
/*l_chart->legend()->setAlignment( Qt::AlignBottom );*/
|
|
l_chart->legend()->setVisible( false );
|
|
|
|
// set-up the date-time axis (X)
|
|
QDateTimeAxis* axisX{ new QDateTimeAxis() };
|
|
axisX->setFormat( "hh:mm" );
|
|
axisX->setTickCount( 25 );
|
|
axisX->setTitleText( PrintSec::printableDate( year, this->getMonthNumber(month), day ) );
|
|
l_chart->addAxis( axisX, Qt::AlignBottom );
|
|
line->attachAxis( axisX );
|
|
|
|
// set-up the count values axis (Y)
|
|
QValueAxis* axisY{ new QValueAxis() };
|
|
axisY->setLabelFormat( "%d" );
|
|
axisY->setTickCount( ( max_value < 8 ) ? max_value : 8 );
|
|
axisY->setMinorTickCount( 4 );
|
|
if ( max_value == 1 ) {
|
|
max_value = 0;
|
|
}
|
|
axisY->setRange( 0, max_value );
|
|
l_chart->addAxis( axisY, Qt::AlignLeft );
|
|
line->attachAxis( axisY) ;
|
|
|
|
// add the chart to the view
|
|
chart->setChart( l_chart );
|
|
chart->setRenderHint(QPainter::Antialiasing);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Crapview::drawCount( QTableWidget* table, QtCharts::QChartView* chart, const QChart::ChartTheme& theme, const QString& web_server, const QString& year, const QString& month, const QString& day, const QString& field ) const
|
|
{
|
|
Result<stats_count_items_t> result;
|
|
this->dbQuery.getItemsCount(
|
|
result,
|
|
web_server,
|
|
year, month, day,
|
|
field );
|
|
if ( result ) {
|
|
// std::vector<std::tuple<QString, int>>
|
|
// [ ( log_item, count ) ]
|
|
auto& items{ result.getData() };
|
|
|
|
// make the pie
|
|
QPieSeries* pie{ new QPieSeries() };
|
|
// cut off exdceeding elements for the chart
|
|
const int max_items{ 15 };
|
|
int count, oth_count{0}, n_rows{0};
|
|
QString item;
|
|
// bring items in reverse order
|
|
stats_count_items_t::const_reverse_iterator iter = items.rbegin();
|
|
while ( iter != items.rend() ) {
|
|
item = iter->second;
|
|
count = iter->first;
|
|
++iter;
|
|
if ( n_rows >= max_items ) {
|
|
oth_count += count;
|
|
} else {
|
|
pie->append( item, count );
|
|
}
|
|
table->insertRow( n_rows );
|
|
auto* ic{ new QTableWidgetItem() };
|
|
ic->setData( Qt::DisplayRole, count );
|
|
table->setItem( n_rows, 0, ic );
|
|
table->setItem( n_rows, 1, new QTableWidgetItem( item ));
|
|
n_rows ++;
|
|
}
|
|
table->verticalHeader()->setVisible( false );
|
|
|
|
if ( oth_count > 0 ) {
|
|
pie->append( TR::tr( "Others" ), oth_count );
|
|
QPieSlice* slice = pie->slices().at( pie->count()-1 );
|
|
slice->setBrush( Qt::gray );
|
|
}
|
|
pie->setPieSize( 0.65 );
|
|
pie->setLabelsVisible( false );
|
|
connect( pie, &QPieSeries::clicked, this, &Crapview::sliceClicked );
|
|
|
|
QChart* p_chart{ new QChart() };
|
|
p_chart->setTheme( theme );
|
|
p_chart->addSeries( pie );
|
|
p_chart->setTitle( field );
|
|
p_chart->legend()->hide();
|
|
|
|
chart->setChart( p_chart );
|
|
chart->setRenderHint( QPainter::Antialiasing );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Crapview::drawDay( QtCharts::QChartView* chart, const QChart::ChartTheme& theme, const QString& web_server, const QString& from_year, const QString& from_month, const QString& from_day, const QString& to_year, const QString& to_month, const QString& to_day, const QString& field , const QString& filter ) const
|
|
{
|
|
Result<stats_day_items_t> result;
|
|
this->dbQuery.getDaytimeCounts(
|
|
result,
|
|
web_server,
|
|
from_year, from_month, from_day,
|
|
to_year, to_month, to_day,
|
|
field, filter );
|
|
if ( result ) {
|
|
// std::unordered_map<int, std::unordered_map<int, int>>
|
|
// { hour : { 10th_minutes : count } }
|
|
auto& items{ result.getData() };
|
|
|
|
// draw the chart
|
|
QString date;
|
|
QColor col{ Qt::GlobalColor::darkGreen };
|
|
QBarSet* b_10{ new QBarSet( "" ) };
|
|
b_10->setColor( col );
|
|
QBarSet* b_20{ new QBarSet( "" ) };
|
|
b_20->setColor( col );
|
|
QBarSet* b_30{ new QBarSet( "" ) };
|
|
if ( to_year.isEmpty() || to_month.isEmpty() || to_day.isEmpty() ) {
|
|
date = PrintSec::printableDate( from_year, this->getMonthNumber(from_month), from_day );
|
|
} else {
|
|
date = QString("%1 %2 %3 %4")
|
|
.arg( TR::tr( "from" ),
|
|
PrintSec::printableDate( from_year, this->getMonthNumber(from_month), from_day ),
|
|
TR::tr( "to" ),
|
|
PrintSec::printableDate( to_year, this->getMonthNumber(to_month), to_day ) );
|
|
}
|
|
b_30->setColor( col );
|
|
QBarSet* b_40{ new QBarSet( "" ) };
|
|
b_40->setColor( col );
|
|
QBarSet* b_50{ new QBarSet( "" ) };
|
|
b_50->setColor( col );
|
|
QBarSet* b_60{ new QBarSet( "" ) };
|
|
b_60->setColor( col );
|
|
|
|
// build the bars upon data
|
|
int count, max_count{0};
|
|
for ( int h{0}; h<24; h++ ) {
|
|
auto& data = items.at( h );
|
|
count = data.at( 0 );
|
|
*b_10 << count;
|
|
if ( count > max_count ) {
|
|
max_count = count;
|
|
}
|
|
count = data.at( 10 );
|
|
*b_20 << count;
|
|
if ( count > max_count ) {
|
|
max_count = count;
|
|
}
|
|
count = data.at( 20 );
|
|
*b_30 << count;
|
|
if ( count > max_count ) {
|
|
max_count = count;
|
|
}
|
|
count = data.at( 30 );
|
|
*b_40 << count;
|
|
if ( count > max_count ) {
|
|
max_count = count;
|
|
}
|
|
count = data.at( 40 );
|
|
*b_50 << count;
|
|
if ( count > max_count ) {
|
|
max_count = count;
|
|
}
|
|
count = data.at( 50 );
|
|
*b_60 << count;
|
|
if ( count > max_count ) {
|
|
max_count = count;
|
|
}
|
|
}
|
|
|
|
// apply the bars to the bars serie
|
|
QBarSeries* bars{ new QBarSeries() };
|
|
bars->append( b_10 ); bars->append( b_20 ); bars->append( b_30 );
|
|
bars->append( b_40 ); bars->append( b_50 ); bars->append( b_60 );
|
|
bars->setBarWidth( 1 );
|
|
|
|
// set-up the bars chart
|
|
QChart* b_chart{ new QChart() };
|
|
b_chart->setTheme( theme );
|
|
b_chart->addSeries( bars );
|
|
b_chart->setTitle( QString("%1: %2").arg( TR::tr( "Time of Day Count" ), field ) );
|
|
b_chart->legend()->setVisible( false );
|
|
/*b_chart->legend()->setAlignment( Qt::AlignBottom );
|
|
b_chart->setAnimationOptions( QChart::SeriesAnimations );*/
|
|
|
|
// craft the X-axis labels
|
|
QStringList categories;
|
|
categories << "00" << "01" << "02" << "03" << "04" << "05" << "06" << "07" << "08" << "09" << "10" << "11"
|
|
<< "12" << "13" << "14" << "15" << "16" << "17" << "18" << "19" << "20" << "21" << "22" << "23";
|
|
|
|
// set-up the time-of-day axis (X)
|
|
QBarCategoryAxis* axisX{ new QBarCategoryAxis() };
|
|
axisX->append( categories );
|
|
axisX->setTitleText( date );
|
|
b_chart->addAxis( axisX, Qt::AlignBottom );
|
|
bars->attachAxis( axisX );
|
|
|
|
// set-up the count values axis (Y)
|
|
QValueAxis* axisY{ new QValueAxis() };
|
|
axisY->setLabelFormat( "%d" );
|
|
axisY->setTickCount( ( max_count < 8 ) ? max_count : 8 );
|
|
axisY->setRange( 0, max_count );
|
|
b_chart->addAxis( axisY, Qt::AlignLeft );
|
|
bars->attachAxis( axisY) ;
|
|
|
|
// apply the chart to the view
|
|
chart->setChart( b_chart );
|
|
chart->setRenderHint( QPainter::Antialiasing );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Crapview::drawRelat( QtCharts::QChartView* chart, const QChart::ChartTheme& theme, const QString& web_server, const QString& from_year, const QString& from_month, const QString& from_day, const QString& to_year, const QString& to_month, const QString& to_day, const QString& field_1, const QString& filter_1, const QString& field_2, const QString& filter_2 ) const
|
|
{
|
|
bool period{ true };
|
|
Result<stats_relat_items_t> result;
|
|
if ( from_year == to_year
|
|
&& from_month == to_month
|
|
&& from_day == to_day ) {
|
|
period &= false;
|
|
this->dbQuery.getRelationalCountsDay(
|
|
result,
|
|
web_server,
|
|
from_year, from_month, from_day,
|
|
field_1, filter_1,
|
|
field_2, filter_2 );
|
|
} else {
|
|
this->dbQuery.getRelationalCountsPeriod(
|
|
result,
|
|
web_server,
|
|
from_year, from_month, from_day,
|
|
to_year, to_month, to_day,
|
|
field_1, filter_1,
|
|
field_2, filter_2 );
|
|
}
|
|
|
|
if ( result ) {
|
|
// std::vector<std::tuple<long long, int>>
|
|
// [ ( epoch_ms, count ) ]
|
|
auto& items{ result.getData() };
|
|
|
|
// draw the relational chart
|
|
QLineSeries* line{ new QLineSeries() };
|
|
// build the line upon data
|
|
int count, max_count{0};
|
|
long long time; // xD
|
|
for ( const auto& item : items ) {
|
|
time = std::get<0>(item);
|
|
count = std::get<1>(item);
|
|
line->append( time, (double)count );
|
|
if ( count > max_count ) {
|
|
max_count = count;
|
|
}
|
|
}
|
|
|
|
// build the area
|
|
QString date;
|
|
QAreaSeries* area{ new QAreaSeries( line ) };
|
|
if ( ! period ) {
|
|
date = PrintSec::printableDate( from_year, this->getMonthNumber(from_month), from_day );
|
|
} else {
|
|
date = QString("%1 %2 %3 %4")
|
|
.arg( TR::tr( "from" ),
|
|
PrintSec::printableDate( from_year, this->getMonthNumber(from_month), from_day ),
|
|
TR::tr( "to" ),
|
|
PrintSec::printableDate( to_year, this->getMonthNumber(to_month), to_day ));
|
|
}
|
|
|
|
// color the area
|
|
QColor col1{ Qt::GlobalColor::red },
|
|
col2{ Qt::GlobalColor::yellow },
|
|
col3{ Qt::GlobalColor::magenta };
|
|
//area->setColor( col );
|
|
QLinearGradient gradient{ QPointF(0, 0), QPointF(0, 1) };
|
|
gradient.setColorAt(0.25, col3.lighter( 70 ) );
|
|
gradient.setColorAt(0.5, col1.lighter( 80 ) );
|
|
gradient.setColorAt(1.0, col2.lighter( 90 ) );
|
|
gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
|
|
area->setBrush( gradient );
|
|
area->setBorderColor( col1.lighter( 50 ) );
|
|
|
|
// fictitious area, just to have another label
|
|
QAreaSeries* area_{ new QAreaSeries( ) };
|
|
area_->setBrush( gradient );
|
|
area_->setBorderColor( col1.lighter( 50 ) );
|
|
|
|
// build the area
|
|
QChart* a_chart{ new QChart() };
|
|
a_chart->setTheme( theme );
|
|
a_chart->addSeries( area );
|
|
a_chart->addSeries( area_ );
|
|
a_chart->setTitle( QString("%1: %2 -> %3").arg( TR::tr( "Time of Day Count" ), field_1, field_2) );
|
|
a_chart->legend()->setVisible( false );
|
|
/*a_chart->legend()->setFont( fonts.at( "main_small" ) );
|
|
a_chart->legend()->setAlignment( Qt::AlignBottom );*/
|
|
|
|
// set-up the date-time axis (X)
|
|
QDateTimeAxis* axisX{ new QDateTimeAxis() };
|
|
if ( period ) {
|
|
//axisX->setLabelsVisible( false );
|
|
axisX->setFormat( "yyyy-MM" );
|
|
int ticks{ this->dbQuery.countMonths( from_year, from_month, to_year, to_month ) };
|
|
if ( ticks == 1 ) {
|
|
axisX->setFormat( "yyyy-MM-dd" );
|
|
ticks = to_day.toInt() - from_day.toInt() +2;
|
|
}
|
|
axisX->setTickCount( ticks+1 );
|
|
} else {
|
|
axisX->setFormat( "hh:mm" );
|
|
axisX->setTickCount( 25 );
|
|
}
|
|
axisX->setTitleText( date );
|
|
a_chart->addAxis( axisX, Qt::AlignBottom );
|
|
area->attachAxis( axisX );
|
|
|
|
// set-up the count values axis (Y)
|
|
QValueAxis* axisY{ new QValueAxis() };
|
|
axisY->setLabelFormat( "%d" );
|
|
axisY->setTickCount( ( max_count < 8 ) ? max_count : 8 );
|
|
axisY->setRange( 0, max_count );
|
|
a_chart->addAxis( axisY, Qt::AlignLeft );
|
|
area->attachAxis( axisY) ;
|
|
|
|
// add the chart to the view
|
|
chart->setChart( a_chart );
|
|
chart->setRenderHint(QPainter::Antialiasing);
|
|
}
|
|
}
|
|
|
|
|
|
// calculate global informations
|
|
const bool Crapview::calcGlobals( std::vector<std::tuple<QString,QString>>& recur_list, std::vector<std::tuple<QString,QString>>& traffic_list, std::vector<std::tuple<QString,QString>>& perf_list, std::vector<QString>& work_list, const QString& web_server ) const
|
|
{
|
|
bool result{ false };
|
|
|
|
if ( ! this->dates.at( this->WebServer_s2i.value( web_server ) ).empty() ) {
|
|
|
|
// { { item, count } } // 0:protocol, 1:method, 1:uri, 3:user-agent
|
|
std::vector<std::unordered_map<QString, unsigned>> recurs{ {}, {}, {}, {} };
|
|
// ( date_str, count )
|
|
std::tuple<QString, int> traf_date;
|
|
// { day_name : total_count }
|
|
std::unordered_map<int, double> traf_day{ {1,0}, {2,0}, {3,0}, {4,0}, {5,0}, {6,0}, {7,0} };
|
|
// { hour : total_count }
|
|
std::unordered_map<int, double> traf_hour{
|
|
{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {5,0}, {6,0}, {7,0}, {8,0}, {9,0}, {10,0}, {11,0},
|
|
{12,0}, {13,0}, {14,0}, {15,0}, {16,0}, {17,0}, {18,0}, {19,0}, {20,0}, {21,0}, {22,0}, {23,0} };
|
|
// [ max, total, num ]
|
|
std::vector<long long> perf_time;
|
|
// [ max, total, num ]
|
|
std::vector<long long> perf_sent;
|
|
// [ max, total, num ]
|
|
std::vector<long long> perf_receiv;
|
|
// count
|
|
long req_count{ 0 };
|
|
|
|
result = this->dbQuery.getGlobalCounts(
|
|
web_server, this->dates.at( this->WebServer_s2i.value( web_server ) ),
|
|
recurs,
|
|
traf_date, traf_day, traf_hour,
|
|
perf_time, perf_sent, perf_receiv,
|
|
req_count );
|
|
|
|
if ( result ) {
|
|
// compose the results
|
|
|
|
// max request elements
|
|
for ( size_t i{0}; i<4ul; i++ ) {
|
|
unsigned max{ 0 };
|
|
QString max_str{ "-" };
|
|
const auto& aux{ recurs.at( i ) };
|
|
for ( const auto& [s,c] : aux ) {
|
|
if ( c > max ) {
|
|
max = c;
|
|
max_str = s;
|
|
}
|
|
}
|
|
recur_list.push_back( std::make_tuple( max_str, QString("%1").arg(max) ) );
|
|
}
|
|
|
|
// max date ever
|
|
traffic_list.push_back( std::make_tuple( std::get<0>(traf_date), QString("%1").arg( std::get<1>(traf_date) ) ) );
|
|
|
|
// max day of the week
|
|
double max{ 0.0 };
|
|
int max_{ 0 };
|
|
for ( const auto& [d,c] : traf_day ) {
|
|
if ( c > max ) {
|
|
max = c;
|
|
max_ = d;
|
|
}
|
|
}
|
|
if ( max_ == 0.0 ) {
|
|
traffic_list.push_back( std::make_tuple( "-", "0" ) );
|
|
} else {
|
|
const int f{ static_cast<int>(max) };
|
|
const int d{ (max<10.0) ? static_cast<int>(max*100.0)%100 : static_cast<int>(max*10.0)%10 };
|
|
QString count{ QString("%1").arg( f ) };
|
|
if ( d > 0 ) {
|
|
count += QString(".%1").arg( d );
|
|
}
|
|
traffic_list.push_back( std::make_tuple( TR::tr(this->dbQuery.DAYS.at(max_).c_str()), count ));
|
|
}
|
|
|
|
// max hour of the day
|
|
max=0.0, max_=-1.0;
|
|
for ( const auto& [h,c] : traf_hour ) {
|
|
if ( c > max ) {
|
|
max = c;
|
|
max_ = h;
|
|
}
|
|
}
|
|
if ( max_ < 0 ) {
|
|
traffic_list.push_back( std::make_tuple( "", "0" ) );
|
|
} else {
|
|
const int f{ static_cast<int>(max) };
|
|
const int d{ (max<10.0) ? static_cast<int>(max*100.0)%100 : static_cast<int>(max*10.0)%10 };
|
|
QString count = QString("%1").arg( f );
|
|
if ( d > 0 ) {
|
|
count += QString(".%1").arg( d );
|
|
}
|
|
QString h{ (max_<10) ? QString("0%1").arg(max_) : QString("%1").arg(max_) };
|
|
traffic_list.push_back( std::make_tuple( h, count ) );
|
|
}
|
|
|
|
// mean/max time-taken
|
|
perf_list.push_back( std::make_tuple(
|
|
QString("%1 ms").arg( (perf_time.at(2)>0ll) ? perf_time.at(1)/perf_time.at(2) : perf_time.at(1) ),
|
|
QString("%1 ms").arg( perf_time.at(0) ) ));
|
|
perf_list.push_back( std::make_tuple(
|
|
QString("%1 B").arg( (perf_sent.at(2)>0ll) ? perf_sent.at(1)/perf_sent.at(2) : perf_time.at(1) ),
|
|
QString("%1 B").arg( perf_sent.at(0) ) ));
|
|
perf_list.push_back( std::make_tuple(
|
|
QString("%1 B").arg( (perf_receiv.at(2)>0ll) ? perf_receiv.at(1)/perf_receiv.at(2) : perf_receiv.at(1) ),
|
|
QString("%1 B").arg( perf_receiv.at(0) ) ));
|
|
|
|
// overall work list
|
|
work_list.push_back( QString("%1").arg( req_count ) );
|
|
|
|
float t = static_cast<float>( perf_time.at(1) );
|
|
if ( t < 0.f ) {
|
|
work_list.push_back( "0" );
|
|
} else {
|
|
int h{0}, m{0}, s{0}, ms{0};
|
|
if ( t > 1000.f ) {
|
|
ms = static_cast<int>( t ) %1000;
|
|
t /= 1000.f;
|
|
}
|
|
if ( t > 60.f ) {
|
|
s = static_cast<int>( t );
|
|
s /= 60;
|
|
if ( s > 60 ) {
|
|
m = s/60;
|
|
s = s%60;
|
|
if ( m > 60 ) {
|
|
h = m/60;
|
|
m = m%60;
|
|
}
|
|
}
|
|
}
|
|
work_list.push_back( QString("%1 h %2 m %3.%4 s").arg(h).arg(m).arg(s).arg(ms) );
|
|
}
|
|
|
|
float b = static_cast<float>( perf_sent.at(1) );
|
|
if ( b < 0.f ) {
|
|
work_list.push_back( "0" );
|
|
} else {
|
|
int f{0}, d{0};
|
|
QString sfx{ "B" };
|
|
if ( b > 1024.f ) {
|
|
b /= 1024.f;
|
|
sfx = "KiB";
|
|
if ( b > 1024.f ) {
|
|
b /= 1024.f;
|
|
sfx = "MiB";
|
|
if ( b > 1024.f ) {
|
|
b /= 1024.f;
|
|
sfx = "GiB";
|
|
}
|
|
}
|
|
}
|
|
f = static_cast<int>( b );
|
|
d = static_cast<int>( b*1000.f ) %1000;
|
|
work_list.push_back( QString("%1.%2 %3").arg(f).arg(d).arg(sfx) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|