Commit 12eba23d authored by Pavel Vainerman's avatar Pavel Vainerman

backported to p8 as 2.8-alt7.M80P.8 (with rpmbph script)

parents 1a3f2de4 026e2664
......@@ -2,6 +2,7 @@
#include <string>
#include <sstream>
#include <getopt.h>
#include <chrono>
#include "Debug.h"
#include "modbus/ModbusRTUMaster.h"
#include "modbus/ModbusHelpers.h"
......@@ -96,7 +97,22 @@ enum Command
// --------------------------------------------------------------------------
static char* checkArg( int ind, int argc, char* argv[] );
// --------------------------------------------------------------------------
struct Interval
{
using time_point = std::chrono::time_point<std::chrono::steady_clock>;
Interval()
:tmStart(std::chrono::steady_clock::now())
{}
uint64_t microseconds()
{
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - tmStart).count();
}
time_point tmStart;
};
// --------------------------------------------------------------------------
int main( int argc, char** argv )
{
// std::ios::sync_with_stdio(false);
......@@ -413,7 +429,6 @@ int main( int argc, char** argv )
{
try
{
switch(cmd)
{
case cmdRead01:
......@@ -426,12 +441,15 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::ReadCoilRetMessage ret = mb.read01(slaveaddr, reg, count);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << (int)ret.bcnt << endl;
cout << "(reply): count=" << (int)ret.bcnt
<< " [" << i.microseconds() << " ms]"
<< endl;
for( int i = 0; i < ret.bcnt; i++ )
{
......@@ -453,12 +471,15 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::ReadInputStatusRetMessage ret = mb.read02(slaveaddr, reg, count);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << (int)ret.bcnt << endl;
cout << "(reply): count=" << (int)ret.bcnt
<< " [" << i.microseconds() << " ms]"
<< endl;
for( int i = 0; i < ret.bcnt; i++ )
{
......@@ -480,12 +501,15 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::ReadOutputRetMessage ret = mb.read03(slaveaddr, reg, count);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count) << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count)
<< " [" << i.microseconds() << " ms]"
<< endl;
for( size_t i = 0; i < ret.count; i++ )
{
......@@ -510,12 +534,15 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::ReadInputRetMessage ret = mb.read04(slaveaddr, reg, count);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count) << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count)
<< " [" << i.microseconds() << " ms]"
<< endl;
for( size_t i = 0; i < ret.count; i++ )
{
......@@ -540,10 +567,13 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::MEIMessageRetRDI ret = mb.read4314(slaveaddr, devID, objID);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): "
<< "[" << i.microseconds() << " ms] "
<< ret << endl;
else
cout << "(reply): devID='" << (int)ret.devID << "' objNum='" << (int)ret.objNum << "'" << endl << ret.dlist << endl;
}
......@@ -559,10 +589,13 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::ForceSingleCoilRetMessage ret = mb.write05(slaveaddr, reg, (bool)val);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): "
<< " [" << i.microseconds() << " ms] "
<< ret << endl;
}
break;
......@@ -576,10 +609,13 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::WriteSingleOutputRetMessage ret = mb.write06(slaveaddr, reg, val);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): "
<< " [" << i.microseconds() << " ms] "
<< ret << endl;
}
break;
......@@ -596,10 +632,13 @@ int main( int argc, char** argv )
ModbusRTU::ForceCoilsMessage msg(slaveaddr, reg);
ModbusRTU::DataBits b(val);
msg.addData(b);
Interval i;
ModbusRTU::ForceCoilsRetMessage ret = mb.write0F(msg);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): "
<< " [" << i.microseconds() << " ms] "
<< ret << endl;
}
break;
......@@ -619,10 +658,13 @@ int main( int argc, char** argv )
for( int i = 0; i < count; i++ )
msg.addData(val);
Interval i;
ModbusRTU::WriteOutputRetMessage ret = mb.write10(msg);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): "
<< " [" << i.microseconds() << " ms] "
<< ret << endl;
}
break;
......@@ -636,12 +678,15 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::DiagnosticRetMessage ret = mb.diag08(slaveaddr, subfunc, dat);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count) << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count)
<< " [" << i.microseconds() << " ms]"
<< endl;
for( size_t i = 0; i < ret.count; i++ )
{
......@@ -719,7 +764,10 @@ int main( int argc, char** argv )
tofile = s.str();
}
Interval i;
mb.fileTransfer( slaveaddr, reg, tofile, tout);
if( verb )
cout << i.microseconds() << " ms" << endl;
}
break;
......
......@@ -84,6 +84,23 @@ enum Command
};
// --------------------------------------------------------------------------
static char* checkArg( int ind, int argc, char* argv[] );
// --------------------------------------------------------------------------
struct Interval
{
using time_point = std::chrono::time_point<std::chrono::steady_clock>;
Interval()
:tmStart(std::chrono::steady_clock::now())
{}
uint64_t microseconds()
{
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - tmStart).count();
}
time_point tmStart;
};
// --------------------------------------------------------------------------
int main( int argc, char** argv )
{
// std::ios::sync_with_stdio(false);
......@@ -352,8 +369,6 @@ int main( int argc, char** argv )
if( ncycles > 0 )
nc = ncycles;
std::chrono::time_point<std::chrono::system_clock> start, end;
while( nc )
{
try
......@@ -370,17 +385,15 @@ int main( int argc, char** argv )
<< endl;
}
start = std::chrono::system_clock::now();
Interval i;
ModbusRTU::ReadCoilRetMessage ret = mb.read01(slaveaddr, reg, count);
end = std::chrono::system_clock::now();
int elapsed_usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << (int)ret.bcnt
<< "(" << ModbusRTU::dat2str(ret.bcnt) << ")"
<< " usec: " << elapsed_usec
<< " [" << i.microseconds() << " ms]"
<< endl;
for( int i = 0; i < ret.bcnt; i++ )
......@@ -406,17 +419,15 @@ int main( int argc, char** argv )
<< endl;
}
start = std::chrono::system_clock::now();
Interval i;
ModbusRTU::ReadInputStatusRetMessage ret = mb.read02(slaveaddr, reg, count);
end = std::chrono::system_clock::now();
int elapsed_usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << (int)ret.bcnt
<< "(" << ModbusRTU::dat2str(ret.bcnt) << ")"
<< " usec: " << elapsed_usec
<< " [" << i.microseconds() << " ms]"
<< endl;
for( int i = 0; i < ret.bcnt; i++ )
......@@ -442,17 +453,15 @@ int main( int argc, char** argv )
<< endl;
}
start = std::chrono::system_clock::now();
Interval i;
ModbusRTU::ReadOutputRetMessage ret = mb.read03(slaveaddr, reg, count);
end = std::chrono::system_clock::now();
int elapsed_usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << (int)ret.count
<< "(" << ModbusRTU::dat2str(ret.count) << ")"
<< " usec: " << elapsed_usec
<< " [" << i.microseconds() << " ms]"
<< endl;
for( size_t i = 0; i < ret.count; i++ )
......@@ -483,17 +492,15 @@ int main( int argc, char** argv )
<< endl;
}
start = std::chrono::system_clock::now();
Interval i;
ModbusRTU::ReadInputRetMessage ret = mb.read04(slaveaddr, reg, count);
end = std::chrono::system_clock::now();
int elapsed_usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << (int)ret.count
<< "(" << ModbusRTU::dat2str(ret.count) << ")"
<< " usec: " << elapsed_usec
<< " [" << i.microseconds() << " ms]"
<< endl;
for( size_t i = 0; i < ret.count; i++ )
......@@ -524,10 +531,13 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::MEIMessageRetRDI ret = mb.read4314(slaveaddr, devID, objID);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): "
<< "[" << i.microseconds() << " ms] "
<< ret << endl;
else
cout << "(reply): devID='" << (int)ret.devID << "' objNum='" << (int)ret.objNum << "'" << endl << ret.dlist << endl;
}
......@@ -543,14 +553,12 @@ int main( int argc, char** argv )
<< endl;
}
start = std::chrono::system_clock::now();
Interval i;
ModbusRTU::ForceSingleCoilRetMessage ret = mb.write05(slaveaddr, reg, (bool)val);
end = std::chrono::system_clock::now();
int elapsed_usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
if( verb )
cout << "(reply): " << ret
<< " usec: " << elapsed_usec
cout << "(reply): " << "[" << i.microseconds() << " ms] "
<< ret
<< endl;
}
break;
......@@ -565,14 +573,12 @@ int main( int argc, char** argv )
<< endl;
}
start = std::chrono::system_clock::now();
Interval i;
ModbusRTU::WriteSingleOutputRetMessage ret = mb.write06(slaveaddr, reg, val);
end = std::chrono::system_clock::now();
int elapsed_usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
if( verb )
cout << "(reply): " << ret
<< " usec: " << elapsed_usec
cout << "(reply): " << "[" << i.microseconds() << " ms] "
<< ret
<< endl;
}
......@@ -591,10 +597,12 @@ int main( int argc, char** argv )
ModbusRTU::ForceCoilsMessage msg(slaveaddr, reg);
ModbusRTU::DataBits b(val);
msg.addData(b);
Interval i;
ModbusRTU::ForceCoilsRetMessage ret = mb.write0F(msg);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): [" << i.microseconds() << " ms] "
<< ret << endl;
}
break;
......@@ -617,10 +625,7 @@ int main( int argc, char** argv )
cout << "}" << endl;
}
start = std::chrono::system_clock::now();
ModbusRTU::WriteOutputMessage msg(slaveaddr, reg);
end = std::chrono::system_clock::now();
int elapsed_usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
for( const auto& v : data )
{
......@@ -639,11 +644,12 @@ int main( int argc, char** argv )
msg.addData(v.d.v);
}
Interval i;
ModbusRTU::WriteOutputRetMessage ret = mb.write10(msg);
if( verb )
cout << "(reply): " << ret
<< " usec: " << elapsed_usec
cout << "(reply): [" << i.microseconds() << " ms] "
<< ret
<< endl;
}
......@@ -659,12 +665,15 @@ int main( int argc, char** argv )
<< endl;
}
Interval i;
ModbusRTU::DiagnosticRetMessage ret = mb.diag08(slaveaddr, subfunc, dat);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count) << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count)
<< " [" << i.microseconds() << " ms]"
<< endl;
for( size_t i = 0; i < ret.count; i++ )
{
......
......@@ -21,6 +21,9 @@
<xsl:variable name="ARGPREFIX">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'arg-prefix'"/></xsl:call-template>
</xsl:variable>
<xsl:variable name="LOGROTATE">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'logrotate'"/></xsl:call-template>
</xsl:variable>
<xsl:template match="/">
<!-- BEGIN CC-FILE -->
......
......@@ -21,6 +21,9 @@
<xsl:variable name="ARGPREFIX">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'arg-prefix'"/></xsl:call-template>
</xsl:variable>
<xsl:variable name="LOGROTATE">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'logrotate'"/></xsl:call-template>
</xsl:variable>
<xsl:template match="/">
<!-- BEGIN CC-FILE -->
......
......@@ -20,6 +20,9 @@
<xsl:variable name="ARGPREFIX">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'arg-prefix'"/></xsl:call-template>
</xsl:variable>
<xsl:variable name="LOGROTATE">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'logrotate'"/></xsl:call-template>
</xsl:variable>
<!-- Генерирование cc-файла -->
<xsl:template match="/">
......
......@@ -20,6 +20,9 @@
<xsl:variable name="ARGPREFIX">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'arg-prefix'"/></xsl:call-template>
</xsl:variable>
<xsl:variable name="LOGROTATE">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'logrotate'"/></xsl:call-template>
</xsl:variable>
<!-- Генерирование cc-файла -->
<xsl:template match="/">
......
......@@ -61,10 +61,10 @@ class <xsl:value-of select="$CLASSNAME"/>_SK:
{
public:
<xsl:if test="not(normalize-space($OID))=''">
<xsl:value-of select="$CLASSNAME"/>_SK( uniset::ObjectId id = uniset::uniset_conf()->getObjectID("<xsl:value-of select="$OID"/>"), xmlNode* node=uniset::uniset_conf()->getNode("<xsl:value-of select="normalize-space($OID)"/>"), const std::string&amp; argprefix="" );
<xsl:value-of select="$CLASSNAME"/>_SK( uniset::ObjectId id = uniset::uniset_conf()->getObjectID("<xsl:value-of select="$OID"/>"), xmlNode* node=uniset::uniset_conf()->getNode("<xsl:value-of select="normalize-space($OID)"/>"), const std::string&amp; argprefix="", xmlNode* globalConfNode=nullptr );
</xsl:if>
<xsl:if test="normalize-space($OID)=''">
<xsl:value-of select="$CLASSNAME"/>_SK( uniset::ObjectId id, xmlNode* node=uniset::uniset_conf()->getNode("<xsl:value-of select="normalize-space($OID)"/>") );
<xsl:value-of select="$CLASSNAME"/>_SK( uniset::ObjectId id, xmlNode* node=uniset::uniset_conf()->getNode("<xsl:value-of select="normalize-space($OID)"/>"), xmlNode* globalConfNode=nullptr );
</xsl:if>
<xsl:value-of select="$CLASSNAME"/>_SK();
......
......@@ -60,10 +60,10 @@ class <xsl:value-of select="$CLASSNAME"/>_SK:
{
public:
<xsl:if test="not(normalize-space($OID))=''">
<xsl:value-of select="$CLASSNAME"/>_SK( uniset::ObjectId id = uniset::uniset_conf()->getObjectID("<xsl:value-of select="$OID"/>"), xmlNode* node=uniset::uniset_conf()->getNode("<xsl:value-of select="normalize-space($CNAME)"/>"), const std::string&amp; argprefix="<xsl:value-of select="normalize-space($ARGPREFIX)"/>" );
<xsl:value-of select="$CLASSNAME"/>_SK( uniset::ObjectId id = uniset::uniset_conf()->getObjectID("<xsl:value-of select="$OID"/>"), xmlNode* node=uniset::uniset_conf()->getNode("<xsl:value-of select="normalize-space($CNAME)"/>"), const std::string&amp; argprefix="<xsl:value-of select="normalize-space($ARGPREFIX)"/>", xmlNode* globalConfNode=nullptr );
</xsl:if>
<xsl:if test="normalize-space($OID)=''">
<xsl:value-of select="$CLASSNAME"/>_SK( uniset::ObjectId id, xmlNode* node=uniset::uniset_conf()->getNode("<xsl:value-of select="normalize-space($CNAME)"/>"), const std::string&amp; argprefix="<xsl:value-of select="normalize-space($ARGPREFIX)"/>" );
<xsl:value-of select="$CLASSNAME"/>_SK( uniset::ObjectId id, xmlNode* node=uniset::uniset_conf()->getNode("<xsl:value-of select="normalize-space($CNAME)"/>"), const std::string&amp; argprefix="<xsl:value-of select="normalize-space($ARGPREFIX)"/>", xmlNode* globalConfNode=nullptr );
</xsl:if>
<xsl:value-of select="$CLASSNAME"/>_SK();
virtual ~<xsl:value-of select="$CLASSNAME"/>_SK();
......
......@@ -14,6 +14,9 @@
<xsl:variable name="OID">
<xsl:call-template name="settings-alone"><xsl:with-param name="varname" select="'ID'"/></xsl:call-template>
</xsl:variable>
<xsl:variable name="LOGROTATE">
<xsl:call-template name="settings-alone"><xsl:with-param name="varname" select="'logrotate'"/></xsl:call-template>
</xsl:variable>
<!-- Генерирование main для UniSet_FSM -->
......
......@@ -18,6 +18,7 @@
<set name="sleep-msec" val="150"/>
<set name="arg-prefix" val="test-"/>
<set name="resetMsgTime" val="300"/>
<set name="logrotate" val="truncate"/>
</settings>
<variables>
<!-- type = [int,str,bool,float]
......
......@@ -26,7 +26,7 @@
Name: libuniset2
Version: 2.8
Release: alt2.M80P.3
Release: alt7.M80P.8
Summary: UniSet - library for building distributed industrial control systems
License: LGPL
......@@ -546,9 +546,24 @@ rm -f %buildroot%_docdir/%oname/html/*.md5
# history of current unpublished changes
%changelog
* Tue Feb 05 2019 Pavel Vainerman <pv@altlinux.ru> 2.8-alt2.M80P.3
* Mon Mar 18 2019 Pavel Vainerman <pv@altlinux.ru> 2.8-alt7.M80P.8
- backport to ALTLinux p8 (by rpmbph script)
* Mon Mar 18 2019 Pavel Vainerman <pv@altlinux.ru> 2.8-alt8
- minor fixes
* Sun Feb 24 2019 Pavel Vainerman <pv@altlinux.ru> 2.8-alt7
- (LogDB): added support write logfiles
* Mon Feb 11 2019 Pavel Vainerman <pv@altlinux.ru> 2.8-alt6
- (TSDB): reopen connection for error "broken pipe"
* Sat Feb 09 2019 Pavel Vainerman <pv@altlinux.ru> 2.8-alt5
- (uniset-codegen): setup logrotate command
* Tue Feb 05 2019 Pavel Vainerman <pv@altlinux.ru> 2.8-alt4
- (PGSQL): fix SIGSEGV in flushInsertBuffer()
* Tue Feb 05 2019 Pavel Vainerman <pv@altlinux.ru> 2.8-alt3
- (admin): fix error in "sendText" funciton
......
......@@ -76,6 +76,7 @@
<set name="class-name" val="TestGen"/>
<set name="msg-count" val="20"/>
<set name="sleep-msec" val="150"/>
<set name="logrotate" val="append"/>
</settings>
<variables>
<!-- type = [int,str,bool,float]
......@@ -285,6 +286,17 @@
А также такой процесс потребляет больше процессорного времени, т.к. постоянно опрашивает "входы" независимо от того, меняли ли они
своё состояние.
\section pg_Codegen_Logrotate Настройка ротации логов
В разделе '<settings>' можно задавать параметр \b logrotate=[truncate|append]. Он определяет как будет обработана
команда SystemMessage::Logrotate, по которой происходит переоткрытие логфайла (если включено ведение логфайла).
- \b truncate - при переоткрытии "обрезать" файл
- \b append - при переоткрытии продолжить писать логи в конец файла
Режим \b append используется по умолчанию. Он удобен для использования совместно с внешней системой ротации логов,
например logrotate. Которая после проведения ротации может обрезать файл и посылать ВСЕМ процессам команду LogRotate по которой
файл логов будет переоткрыт, если он был заархивирован. При этом те процессы чей файл не был заархивирован, продолжат
писать дальше в конец логфайла.
\section pg_Codegen_Templ_Alone Шаблон 'Alone'
Шаблон \b "Alone" предназначен для генерирования \b без \b использования специального xml-файла с описанием переменных.
Генерирование происходит непосредственно по конфигурационному файлу проекта. Для этого всё-равно необходимо создать
......
......@@ -365,9 +365,16 @@ bool BackendOpenTSDB::flushBuffer()
return true;
}
catch( Poco::IOException& ex )
{
mywarn << "(flushBuffer): (io): " << ex.displayText() << endl;
lastError = ex.displayText();
if( !reconnect() )
askTimer(tmReconnect, reconnectTime);
}
catch( std::exception& ex )
{
mywarn << "(flushBuffer): " << ex.what() << endl;
mywarn << "(flushBuffer): (std): " << ex.what() << endl;
lastError = ex.what();
}
......
......@@ -212,12 +212,9 @@ void DBServer_PostgreSQL::flushBuffer()
//--------------------------------------------------------------------------------------------
void DBServer_PostgreSQL::flushInsertBuffer()
{
if( !db || !connect_ok )
if( ibufSize > ibufMaxSize )
{
if( ibufSize < ibufMaxSize )
return;
dbcrit << myname << "(flushWriteBuffer): DB not connected!"
dbcrit << myname << "(flushWriteBuffer): "
<< " buffer[" << ibufSize << "] overflow! LOST DATA..." << endl;
// Чистим заданное число
......@@ -228,26 +225,29 @@ void DBServer_PostgreSQL::flushInsertBuffer()
// Удаляем последние (новые)
if( lastRemove )
{
std::advance(beg, -delnum);
end = std::prev(end, delnum);
}
else
{
// Удаляем первые (старые)
std::advance(end, delnum);
beg = std::next(beg, delnum);
}
if( beg != ibuf.end() )
ibuf.erase(beg, end);
// ibufSize - беззнаковое, так что надо аккуратно
ibufSize = (delnum < ibufSize) ? (ibufSize - delnum) : 0;
dbwarn << myname << "(flushInsertBuffer): overflow: clear data " << delnum << " records." << endl;
return;
}
if( ibufSize == 0 )
return;
if( !db || !connect_ok )
return;
dbinfo << myname << "(flushInsertBuffer): write insert buffer[" << ibufSize << "] to DB.." << endl;
if( !writeInsertBufferToDB("main_history", tblcols, ibuf) )
......
......@@ -3,5 +3,5 @@
ulimit -Sc 1000000
uniset2-start.sh -f ./uniset2-pgsql-dbserver --confile test.xml --name DBServer1 \
--pgsql-dbserver-buffer-size 100 \
--pgsql-buffer-size 100 \
--pgsql-log-add-levels any $*
......@@ -190,6 +190,18 @@ LogDB::LogDB( const string& name, int argc, const char* const* argv, const strin
if( !dbDisabled )
l->signal_on_read().connect(sigc::mem_fun(this, &LogDB::addLog));
auto lfile = sit.getProp("logfile");
if( !lfile.empty() )
{
l->logfile = make_shared<DebugStream>();
l->logfile->logFile(lfile, false);
l->logfile->level(Debug::ANY);
l->logfile->showDateTime(false);
l->logfile->showLogType(false);
l->logfile->disableOnScreen();
l->signal_on_read().connect(sigc::mem_fun(this, &LogDB::log2File));
}
// l->set(loop);
logservers.push_back(l);
......@@ -398,6 +410,14 @@ void LogDB::addLog( LogDB::Log* log, const string& txt )
qbuf.emplace(q.str());
}
//--------------------------------------------------------------------------------------------
void LogDB::log2File( LogDB::Log* log, const string& txt )
{
if( !log->logfile || !log->logfile->isOnLogFile() )
return;
log->logfile->any() << txt << endl;
}
//--------------------------------------------------------------------------------------------
size_t LogDB::getCountOfRecords( const std::string& logname )
{
ostringstream q;
......
......@@ -54,6 +54,7 @@ namespace uniset
- \ref sec_LogDB_WEBSOCK
- \ref sec_LogDB_DETAIL
- \ref sec_LogDB_ADMIN
- \ref sec_LogDB_LOGFILE
\section sec_LogDB_Comm Общее описание работы LogDB
......@@ -72,7 +73,7 @@ namespace uniset
<LogDB name="LogDB" ...>
<logserver name="" ip=".." port=".." cmd=".." description=".."/>
<logserver name="" ip=".." port=".." cmd=".." description=".."/>
<logserver name="" ip=".." port=".." cmd=".."/>
<logserver name="" ip=".." port=".." cmd=".." logfile=".."/>
</LogDB>
\endcode
......@@ -135,6 +136,10 @@ namespace uniset
Количество создаваемых websocket-ов можно ограничить при помощи параметр maxWebsockets (--prefix-ws-max).
\section sec_LogDB_LOGFILE LogDB: Файлы логов
Несмотря на то, что все логи сохраняются в БД, их так же можно писать в файлы.
Для этого каждому логу достаточно указать свойство \b logfile в настройках (см. \ref sec_LogDB_Conf)
\section sec_LogDB_DETAIL LogDB: Технические детали
Вся реализация построена на "однопоточном" eventloop. В нём происходит,
......@@ -207,6 +212,7 @@ namespace uniset
void onCheckBuffer( ev::timer& t, int revents );
void onActivate( ev::async& watcher, int revents ) ;
void addLog( Log* log, const std::string& txt );
void log2File( Log* log, const std::string& txt );
size_t getCountOfRecords( const std::string& logname = "" );
size_t getFirstOfOldRecord( size_t maxnum );
......@@ -270,6 +276,7 @@ namespace uniset
std::string description;
std::shared_ptr<DebugStream> dblog;
std::shared_ptr<DebugStream> logfile;
bool isConnected() const;
......
<?xml version="1.0" encoding="utf-8"?>
<LogDB name="LogDB">
<logserver name="logserver1" ip="localhost" port="3333" cmd="" description="Лог сервер процесса управления N1"/>
<logserver name="logserver1" ip="localhost" port="3333" cmd="" description="Лог сервер процесса управления N1" logfile="/tmp/uniset-test.log"/>
</LogDB>
......@@ -86,9 +86,21 @@ function logdb_test_http_list()
logdb_error "test_http_list" "get list must contain 'logserver1'"
return 1
}
# see config
LOGFILE="/tmp/uniset-test.log"
function logdb_test_logfile()
{
test -f $LOGFILE && return 0
logdb_error "test_logfile" "not found logfile: $LOGFILE"
return 1
}
# ------------------------------------------------------------------------------------------
function logdb_run_all_tests()
{
rm -f $LOGFILE
logdb_run_logserver || return 1
sleep 3
logdb_run || return 1
......@@ -98,6 +110,10 @@ function logdb_run_all_tests()
logdb_test_count || RET=1
logdb_test_http_count || RET=1
logdb_test_http_list || RET=1
logdb_test_logfile || RET 1
# ==== finished ===
rm -f $LOGFILE
}
create_test_db || exit 1
......
......@@ -1815,7 +1815,7 @@ namespace uniset
i++;
}
std::advance(it, sub);
it = std::next(it, sub);
regID += sub;
}
else
......
......@@ -308,23 +308,26 @@ TEST_CASE("(0x0F): force multiple coils", "[modbus][mbslave][mbtcpslave]")
}
}
#endif
TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcpslave]")
TEST_CASE("(0x10): write one register", "[modbus][mbslave][mbtcpslave]")
{
InitTest();
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG = 18;
SECTION("Test: write one register")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr, tREG);
msg.addData(10);
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 1 );
REQUIRE( ui->getValue(tID) == 10 );
}
SECTION("Test: write 3 register")
{
}
TEST_CASE("(0x10): write 3 register", "[modbus][mbslave][mbtcpslave][write3]")
{
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG = 18;
ModbusRTU::WriteOutputMessage msg(slaveaddr, tREG);
msg.addData(10);
msg.addData(11);
......@@ -335,9 +338,12 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
REQUIRE( ui->getValue(tID) == 10 );
REQUIRE( ui->getValue(tID + 1) == 11 );
REQUIRE( ui->getValue(tID + 2) == 1 ); // 1 - т.к. это "DI"
}
SECTION("Test: write negative value")
{
}
TEST_CASE("(0x10): write negative value", "[modbus][mbslave][mbtcpslave]")
{
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG = 18;
ModbusRTU::WriteOutputMessage msg(slaveaddr, tREG);
msg.addData(-10);
msg.addData(-100);
......@@ -346,9 +352,12 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
REQUIRE( ret.quant == 2 );
REQUIRE( (int16_t)ui->getValue(tID) == -10 );
REQUIRE( (int16_t)ui->getValue(tID + 1) == -100 );
}
SECTION("Test: write zero registers")
{
}
TEST_CASE("(0x10): write zero registers", "[modbus][mbslave][mbtcpslave]")
{
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG = 18;
ModbusRTU::WriteOutputMessage msg(slaveaddr, tREG);
msg.addData(0);
msg.addData(0);
......@@ -359,9 +368,9 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
REQUIRE( ui->getValue(tID) == 0 );
REQUIRE( ui->getValue(tID + 1) == 0 );
REQUIRE( ui->getValue(tID + 2) == 0 );
}
SECTION("Test: write OVERFLOW VALUE")
{
}
TEST_CASE("(0x10): write OVERFLOW VALUE", "[modbus][mbslave][mbtcpslave]")
{
WARN("FIXME: what to do in this situation?!");
#if 0
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(slaveaddr, 15, 100000);
......@@ -369,9 +378,12 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
REQUIRE( ret.data == 34464 );
REQUIRE( ui->getValue(1008) == 34464 );
#endif
}
SECTION("Test: write 2 good registers and unknown register")
{
}
TEST_CASE("(0x10): write 2 good registers and unknown register", "[modbus][mbslave][mbtcpslave]")
{
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG = 18;
ModbusRTU::WriteOutputMessage msg(slaveaddr, tREG + 1);
msg.addData(10);
msg.addData(11);
......@@ -383,9 +395,12 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
REQUIRE( ui->getValue(tID + 1) == 10 );
REQUIRE( ui->getValue(tID + 2) == 1 ); // 1 - т.к. это "DI"
REQUIRE( ui->getValue(tID + 3) == 0 );
}
SECTION("Test: write ALL unknown registers")
{
}
TEST_CASE("(0x10): write ALL unknown registers", "[modbus][mbslave][mbtcpslave]")
{
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG = 18;
ModbusRTU::WriteOutputMessage msg(slaveaddr, tREG + 20000);
msg.addData(10);
msg.addData(11);
......@@ -399,9 +414,12 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
SECTION("Test: write bad format packet..(incorrect data count)")
{
}
TEST_CASE("(0x10): write bad format packet..(incorrect data count)", "[modbus][mbslave][mbtcpslave]")
{
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG = 18;
ModbusRTU::WriteOutputMessage msg(slaveaddr, tREG + 20000);
msg.addData(10);
msg.addData(11);
......@@ -416,9 +434,12 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
SECTION("Test: write bad format packet..(incorrect size of bytes)")
{
}
TEST_CASE("(0x10): write bad format packet..(incorrect size of bytes)", "[modbus][mbslave][mbtcpslave]")
{
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG = 18;
ModbusRTU::WriteOutputMessage msg(slaveaddr, tREG + 20000);
msg.addData(10);
msg.addData(11);
......@@ -433,7 +454,6 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
}
TEST_CASE("Read(0x03,0x04): vtypes..", "[modbus][mbslave][mbread][mbtcpslave]")
......
......@@ -8,7 +8,7 @@
ВСЕ ВАШИ ИЗМЕНЕНИЯ БУДУТ ПОТЕРЯНЫ.
*/
// --------------------------------------------------------------------------
// generate timestamp: 2019-02-02+03:00
// generate timestamp: 2019-02-11+03:00
// -----------------------------------------------------------------------------
#ifndef UObject_SK_H_
#define UObject_SK_H_
......@@ -29,7 +29,7 @@ class UObject_SK:
public uniset::UniSetObject
{
public:
UObject_SK( uniset::ObjectId id, xmlNode* node=uniset::uniset_conf()->getNode("UObject"), const std::string& argprefix="" );
UObject_SK( uniset::ObjectId id, xmlNode* node=uniset::uniset_conf()->getNode("UObject"), const std::string& argprefix="", xmlNode* globalConfNode=nullptr );
UObject_SK();
virtual ~UObject_SK();
......
......@@ -11,7 +11,7 @@
ВСЕ ВАШИ ИЗМЕНЕНИЯ БУДУТ ПОТЕРЯНЫ.
*/
// --------------------------------------------------------------------------
// generate timestamp: 2019-02-02+03:00
// generate timestamp: 2019-02-11+03:00
// -----------------------------------------------------------------------------
#include <memory>
#include <iomanip>
......@@ -56,6 +56,21 @@ end_private(false)
throw uniset::Exception( std::string(myname+": init failed!!!") );
}
// -----------------------------------------------------------------------------
// ( val, confval, globalval, default val )
static const std::string init4_str( const std::string& s1, const std::string& s2,
const std::string& s3, const std::string& s4 )
{
if( !s1.empty() )
return s1;
if( !s2.empty() )
return s2;
if( !s3.empty() )
return s3;
return s4;
}
// -----------------------------------------------------------------------------
// ( val, confval, default val )
static const std::string init3_str( const std::string& s1, const std::string& s2, const std::string& s3 )
{
......@@ -80,7 +95,7 @@ static uniset::ObjectId init_node( xmlNode* cnode, const std::string& prop )
return conf->getNodeID(conf->getProp(cnode,prop));
}
// -----------------------------------------------------------------------------
UObject_SK::UObject_SK( ObjectId id, xmlNode* cnode, const std::string& _argprefix ):
UObject_SK::UObject_SK( ObjectId id, xmlNode* cnode, const std::string& _argprefix, xmlNode* globalnode ):
UniSetObject(id),
// Инициализация идентификаторов (имена берутся из конф. файла)
......@@ -179,7 +194,7 @@ end_private(false)
if( s_resetTime.empty() ) // -V547
s_resetTime = "500";
resetMsgTime = uni_atoi(init3_str(conf->getArgParam("--" + argprefix + "resetMsgTime"),conf->getProp(cnode,"resetMsgTime"),s_resetTime));
resetMsgTime = uni_atoi(init4_str(conf->getArgParam("--" + argprefix + "resetMsgTime"),conf->getProp(cnode,"resetMsgTime"),conf->getProp(globalnode,"resetMsgTime"), s_resetTime));
ptResetMsg.setTiming(resetMsgTime);
int sm_tout = conf->getArgInt("--" + argprefix + "sm-ready-timeout","");
......@@ -190,7 +205,7 @@ end_private(false)
else
smReadyTimeout = sm_tout;
smTestID = conf->getSensorID(init3_str(conf->getArgParam("--" + argprefix + "sm-test-id"),conf->getProp(cnode,"smTestID"),""));
smTestID = conf->getSensorID(init4_str(conf->getArgParam("--" + argprefix + "sm-test-id"),conf->getProp(cnode,"smTestID"),conf->getProp(globalnode,"smTestID"),""));
if( smTestID == DefaultObjectId ) // -V547
......@@ -491,7 +506,9 @@ void UObject_SK::preSysCommand( const SystemMessage* _sm )
string fname( log()->getLogFile() );
if( !fname.empty() )
{
mylog->logFile(fname.c_str(),true);
mylog->logFile(fname.c_str(),false);
mylogany << myname << "(preSysCommand): ***************** mylog LOG ROTATE *****************" << endl;
}
......
......@@ -10,7 +10,7 @@
// but should be adaptable to any project.
// (c) 2002 adapted for UniSet by Lav, GNU LGPL license
// Modify for UniSet by pv@eterspft.ru, GNU LGPL license
// Modify for UniSet by pv@etersoft.ru, GNU LGPL license
#ifndef DEBUGSTREAM_H
#define DEBUGSTREAM_H
......@@ -68,7 +68,7 @@ struct Debug
If you want to have debug output from time critical code you should
use this construct:
if (debug..is_info()) {
if (debug.is_info()) {
debug << "...debug output...\n";
}
......@@ -160,6 +160,12 @@ class DebugStream : public std::ostream
logFile("");
}
// enable print on screen
void enableOnScreen();
// disable print onscreen
void disableOnScreen();
/// Returns true if t is part of the current debug level.
inline bool debugging(Debug::type t = Debug::ANY) const noexcept
{
......@@ -297,6 +303,7 @@ class DebugStream : public std::ostream
std::string logname = { "" };
bool isWriteLogFile = { false };
bool onScreen = { true };
};
// ------------------------------------------------------------------------------------------------
#endif
......@@ -134,11 +134,39 @@ void DebugStream::logFile( const std::string& f, bool truncate )
mode |= truncate ? ios::trunc : ios::app;
internal->fbuf.open(f.c_str(), mode);
if( onScreen )
{
delete rdbuf(new threebuf(cerr.rdbuf(),
&internal->fbuf, &internal->sbuf));
}
else
{
// print to cerr disabled
delete rdbuf(new teebuf(&internal->fbuf, &internal->sbuf));
}
}
else
{
if( onScreen )
delete rdbuf(new teebuf(cerr.rdbuf(), &internal->sbuf));
else
delete rdbuf(&internal->sbuf);
}
}
//--------------------------------------------------------------------------
void DebugStream::enableOnScreen()
{
onScreen = true;
// reopen streams
logFile(fname,false);
}
//--------------------------------------------------------------------------
void DebugStream::disableOnScreen()
{
onScreen = false;
// reopen streams
logFile(fname,false);
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::debug(Debug::type t) noexcept
......
......@@ -430,6 +430,11 @@ void LogReader::readlogs( const std::string& _addr, int _port, LogServerTypes::C
{
cerr << "(LogReader): " << e.displayText() << " (" << _addr << ")" << endl;
}
catch( Poco::IOException& e )
{
cerr << "(LogReader): " << e.displayText() << " (" << _addr << ")" << endl;
disconnect();
}
catch( const std::exception& ex )
{
cerr << "(LogReader): " << ex.what() << endl;
......@@ -470,6 +475,10 @@ void LogReader::sendCommand(LogServerTypes::lsMessage& msg, bool verbose )
{
cerr << "(LogReader): send error: " << e.displayText() << endl; // " (" << _addr << ")" << endl;
}
catch( Poco::IOException& ex )
{
cerr << "(LogReader): send error: " << ex.displayText() << endl;
}
catch( const std::exception& ex )
{
cerr << "(LogReader): send error: " << ex.what() << endl;
......
......@@ -128,7 +128,7 @@ void ObjectRepository::registration(const string& name, const ObjectPtr oRef, co
}
catch(const CosNaming::NamingContext::AlreadyBound&)
{
uwarn << "(registration): " << name << " уже зарегестрирован в " << section << "!!!" << endl;
uwarn << "(registration): " << name << " уже зарегистрирован в " << section << "!!!" << endl;
if( !force )
throw ObjectNameAlready();
......
......@@ -156,6 +156,9 @@ string UniXML::getProp2(const xmlNode* node, const string& name, const string& d
// -----------------------------------------------------------------------------
string UniXML::getProp(const xmlNode* node, const string& name) noexcept
{
if( !node )
return "";
xmlChar* text = ::xmlGetProp((xmlNode*)node, (const xmlChar*)name.c_str());
if( text == NULL )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment