Add config option to redirect external helpers error output to a file

This commit is contained in:
Jean-Francois Dockes 2021-03-03 17:54:44 +01:00
parent a4b3aff5c4
commit ae2b4577c3
4 changed files with 70 additions and 50 deletions

View File

@ -35,7 +35,7 @@
using namespace std; using namespace std;
MEAdv::MEAdv(int maxsecs) MEAdv::MEAdv(int maxsecs)
: m_filtermaxseconds(maxsecs) : m_filtermaxseconds(maxsecs)
{ {
m_start = time(0L); m_start = time(0L);
} }
@ -129,18 +129,18 @@ bool MimeHandlerExec::skip_to_document(const string& ipath)
bool MimeHandlerExec::next_document() bool MimeHandlerExec::next_document()
{ {
if (m_havedoc == false) if (m_havedoc == false)
return false; return false;
m_havedoc = false; m_havedoc = false;
if (missingHelper) { if (missingHelper) {
LOGDEB("MimeHandlerExec::next_document(): helper known missing\n"); LOGDEB("MimeHandlerExec::next_document(): helper known missing\n");
return false; return false;
} }
if (params.empty()) { if (params.empty()) {
// Hu ho // Hu ho
LOGERR("MimeHandlerExec::next_document: empty params\n"); LOGERR("MimeHandlerExec::next_document: empty params\n");
m_reason = "RECFILTERROR BADCONFIG"; m_reason = "RECFILTERROR BADCONFIG";
return false; return false;
} }
// Command name // Command name
@ -150,7 +150,7 @@ bool MimeHandlerExec::next_document()
vector<string>myparams(params.begin() + 1, params.end()); vector<string>myparams(params.begin() + 1, params.end());
myparams.push_back(m_fn); myparams.push_back(m_fn);
if (!m_ipath.empty()) if (!m_ipath.empty())
myparams.push_back(m_ipath); myparams.push_back(m_ipath);
// Execute command, store the output // Execute command, store the output
string& output = m_metaData[cstr_dj_keycontent]; string& output = m_metaData[cstr_dj_keycontent];
@ -162,45 +162,49 @@ bool MimeHandlerExec::next_document()
mexec.putenv(m_forPreview ? "RECOLL_FILTER_FORPREVIEW=yes" : mexec.putenv(m_forPreview ? "RECOLL_FILTER_FORPREVIEW=yes" :
"RECOLL_FILTER_FORPREVIEW=no"); "RECOLL_FILTER_FORPREVIEW=no");
mexec.setrlimit_as(m_filtermaxmbytes); mexec.setrlimit_as(m_filtermaxmbytes);
std::string errfile;
m_config->getConfParam("helperlogfilename", errfile);
if (!errfile.empty()) {
mexec.setStderr(errfile);
}
int status; int status;
try { try {
status = mexec.doexec(cmd, myparams, 0, &output); status = mexec.doexec(cmd, myparams, 0, &output);
} catch (HandlerTimeout) { } catch (HandlerTimeout) {
LOGERR("MimeHandlerExec: handler timeout\n" ); LOGERR("MimeHandlerExec: handler timeout\n" );
status = 0x110f; status = 0x110f;
} catch (CancelExcept) { } catch (CancelExcept) {
LOGERR("MimeHandlerExec: cancelled\n" ); LOGERR("MimeHandlerExec: cancelled\n" );
status = 0x110f; status = 0x110f;
} }
if (status) { if (status) {
LOGERR("MimeHandlerExec: command status 0x" << LOGERR("MimeHandlerExec: command status 0x" <<
std::hex << status << std::dec << " for " << cmd << "\n"); std::hex << status << std::dec << " for " << cmd << "\n");
if (WIFEXITED(status) && WEXITSTATUS(status) == 127) { if (WIFEXITED(status) && WEXITSTATUS(status) == 127) {
// That's how execmd signals a failed exec (most probably // That's how execmd signals a failed exec (most probably
// a missing command). Let'hope no filter uses the same value as // a missing command). Let'hope no filter uses the same value as
// an exit status... Disable myself permanently and signal the // an exit status... Disable myself permanently and signal the
// missing cmd. // missing cmd.
missingHelper = true;
m_reason = string("RECFILTERROR HELPERNOTFOUND ") + cmd;
} else if (output.find("RECFILTERROR") == 0) {
// If the output string begins with RECFILTERROR, then it's
// interpretable error information out from a recoll script
m_reason = output;
list<string> lerr;
stringToStrings(output, lerr);
if (lerr.size() > 2) {
list<string>::iterator it = lerr.begin();
it++;
if (*it == "HELPERNOTFOUND") {
// No use trying again and again to execute this filter,
// it won't work.
missingHelper = true; missingHelper = true;
m_reason = string("RECFILTERROR HELPERNOTFOUND ") + cmd;
} else if (output.find("RECFILTERROR") == 0) {
// If the output string begins with RECFILTERROR, then it's
// interpretable error information out from a recoll script
m_reason = output;
list<string> lerr;
stringToStrings(output, lerr);
if (lerr.size() > 2) {
list<string>::iterator it = lerr.begin();
it++;
if (*it == "HELPERNOTFOUND") {
// No use trying again and again to execute this filter,
// it won't work.
missingHelper = true;
}
}
} }
} return false;
}
return false;
} }
finaldetails(); finaldetails();
@ -216,19 +220,19 @@ void MimeHandlerExec::handle_cs(const string& mt, const string& icharset)
// "default", we use the default input charset value defined in // "default", we use the default input charset value defined in
// recoll.conf (which may vary depending on directory) // recoll.conf (which may vary depending on directory)
if (charset.empty()) { if (charset.empty()) {
charset = cfgFilterOutputCharset.empty() ? cstr_utf8 : charset = cfgFilterOutputCharset.empty() ? cstr_utf8 :
cfgFilterOutputCharset; cfgFilterOutputCharset;
if (!stringlowercmp("default", charset)) { if (!stringlowercmp("default", charset)) {
charset = m_dfltInputCharset; charset = m_dfltInputCharset;
} }
} }
m_metaData[cstr_dj_keyorigcharset] = charset; m_metaData[cstr_dj_keyorigcharset] = charset;
// If this is text/plain transcode_to/check utf-8 // If this is text/plain transcode_to/check utf-8
if (!mt.compare(cstr_textplain)) { if (!mt.compare(cstr_textplain)) {
(void)txtdcode("mh_exec/m"); (void)txtdcode("mh_exec/m");
} else { } else {
m_metaData[cstr_dj_keycharset] = charset; m_metaData[cstr_dj_keycharset] = charset;
} }
} }
@ -237,16 +241,16 @@ void MimeHandlerExec::finaldetails()
// The default output mime type is html, but it may be defined // The default output mime type is html, but it may be defined
// otherwise in the filter definition. // otherwise in the filter definition.
m_metaData[cstr_dj_keymt] = cfgFilterOutputMtype.empty() ? cstr_texthtml : m_metaData[cstr_dj_keymt] = cfgFilterOutputMtype.empty() ? cstr_texthtml :
cfgFilterOutputMtype; cfgFilterOutputMtype;
if (!m_forPreview && !m_nomd5) { if (!m_forPreview && !m_nomd5) {
string md5, xmd5, reason; string md5, xmd5, reason;
if (MD5File(m_fn, md5, &reason)) { if (MD5File(m_fn, md5, &reason)) {
m_metaData[cstr_dj_keymd5] = MD5HexPrint(md5, xmd5); m_metaData[cstr_dj_keymd5] = MD5HexPrint(md5, xmd5);
} else { } else {
LOGERR("MimeHandlerExec: cant compute md5 for [" << m_fn << "]: " << LOGERR("MimeHandlerExec: cant compute md5 for [" << m_fn << "]: " <<
reason << "\n"); reason << "\n");
} }
} }
handle_cs(m_metaData[cstr_dj_keymt]); handle_cs(m_metaData[cstr_dj_keymt]);

View File

@ -63,6 +63,11 @@ bool MimeHandlerExecMultiple::startCmd()
m_cmd.setrlimit_as(m_filtermaxmbytes); m_cmd.setrlimit_as(m_filtermaxmbytes);
m_adv.setmaxsecs(m_filtermaxseconds); m_adv.setmaxsecs(m_filtermaxseconds);
m_cmd.setAdvise(&m_adv); m_cmd.setAdvise(&m_adv);
std::string errfile;
m_config->getConfParam("helperlogfilename", errfile);
if (!errfile.empty()) {
m_cmd.setStderr(errfile);
}
// Build parameter list: delete cmd name // Build parameter list: delete cmd name
vector<string>myparams(params.begin() + 1, params.end()); vector<string>myparams(params.begin() + 1, params.end());

View File

@ -660,6 +660,17 @@ logfilename = stderr
# <brief>Override logfilename for the indexer.</brief><descr></descr></var> # <brief>Override logfilename for the indexer.</brief><descr></descr></var>
#idxlogfilename = stderr #idxlogfilename = stderr
# <var name="helperlogfilename" type="fn">
#
# <brief>Destination file for external helpers standard error
# output.</brief>
#
# <descr>The external program error output is left alone by default,
# e.g. going to the terminal when the recoll[index] program is executed
# from the command line. Use /dev/null or a file inside a non-existent
# directory to completely suppress the output.</brief></var>
#helperlogfilename=
# <var name="daemloglevel" type="int"> # <var name="daemloglevel" type="int">
# #
# <brief>Override loglevel for the indexer in real time # <brief>Override loglevel for the indexer in real time

View File

@ -168,7 +168,7 @@ public:
bool waitIdle() { bool waitIdle() {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::mutex> lock(m_mutex);
if (!ok()) { if (!ok()) {
LOGERR("WorkQueue::waitIdle:" << m_name << ": not ok\n"); LOGINF("WorkQueue::waitIdle:" << m_name << ": queue already closed\n");
return false; return false;
} }