HylaFAX The world's
most advanced open source fax server
|
|
[
Date Prev][
Date Next][
Thread Prev][
Thread Next]
[
Date Index]
[
Thread Index]
Re: [hylafax-users] Reporting Needs
David,
Attached is a patch which does two things.
1) it adds SUBMIT records to xferfaxlog. This will permit you to take a
look at the SUBMIT record and the corresponding SEND record(s) (and
perhaps a corresponding UNSENT record) to determine how long that job
was in the queue. Compare the date values (the first column in each
record).
2) it adds a new "FaxAccounting" feature. Create an executable (i.e.
shell script with the execute bit set) called
/var/spool/hylafax/etc/FaxAccounting. Any time records are written to
xferfaxlog this executable will be run with the record column values as
command-line parameters. This will permit you to easily attach an
external database (or whatever) to HylaFAX for accounting purposes (in
other words, no need to parse xferfaxlog). Then you can easily perform
whatever statistical analysis or accounting measures that you need from
there.
Hope this helps,
Thanks,
Lee.
Lee Howard wrote:
David Guthu wrote:
Does anyone know of any reporting available with historical
information about how many items are queued to be sent, and what the
status of available resources are, etc etc? I need some really
detailed information about queued time to insure that a service level
defined is being met by the resources allocated. Any help is greatly
appreciated. Does IFAX Enterprise verison offer this?
Although such a feature could be added to HylaFAX, I would think that
it should be a fairly easy task to run a cron job parsing faxstat
output to come up with a relatively good view of the queue size over
time and the modem status.
One thing that I do think could be added to HylaFAX that would make a
significant improvement with respect to queue management would be to
add "SUBMIT" records to xferfaxlog. That way xferfaxstats or
something could parse the average time-in-queue for each destination
or whatever. If that average gets too high, then it's time to add
modems/lines.
Lee.
____________________ HylaFAX(tm) Users Mailing List
_______________________
To subscribe/unsubscribe, click
http://lists.hylafax.org/cgi-bin/lsg2.cgi
On UNIX: mail -s unsubscribe hylafax-users-request@xxxxxxxxxxx <
/dev/null
*To learn about expensive HylaFAX(tm) support, mail sales@xxxxxxxxx*
diff -Nru hylafax.orig/faxd/FaxAcctInfo.c++ hylafax/faxd/FaxAcctInfo.c++
--- hylafax.orig/faxd/FaxAcctInfo.c++ 2005-11-14 08:33:31.000000000 -0800
+++ hylafax/faxd/FaxAcctInfo.c++ 2005-11-15 15:24:36.518816560 -0800
@@ -40,28 +40,43 @@
{
bool ok = false;
int fd = Sys::open(FAX_XFERLOG, O_RDWR|O_CREAT|O_APPEND, 0644);
+
+ char timebuf[80];
+ strftime(timebuf, sizeof (timebuf), "%D %H:%M", localtime(&start));
+
+ char jobtagbuf[80];
+ u_int i = 0;
+ char c;
+ for (const char* cp = jobtag; (c = *cp); cp++) {
+ if (i == sizeof (jobtagbuf)-2) // truncate string
+ break;
+ if (c == '\t') // tabs are field delimiters
+ c = ' ';
+ else if (c == '"') // escape quote marks
+ jobtagbuf[i++] = '\\';
+ jobtagbuf[i++] = c;
+ }
+ jobtagbuf[i] = '\0';
+
+ fxStr paramsbuf = fxStr::format("%u", params);
+ fxStr npagesbuf = fxStr::format("%d", npages);
+ fxStr durationbuf = fxStr::format("%s", fmtTime(duration));
+ fxStr conntimebuf = fxStr::format("%s", fmtTime(conntime));
+
+ fxStr callid_formatted = "";
+ for (i = 2; i < callid.size(); i++) {
+ if (i > 2) callid_formatted.append("::");
+ callid_formatted.append(callid[i]);
+ }
+
if (fd >= 0) {
fxStackBuffer record;
- char buf[80];
- strftime(buf, sizeof (buf), "%D %H:%M", localtime(&start));
- record.put(buf); // $ 1 = time
+ record.put(timebuf); // $ 1 = time
record.fput("\t%s", cmd); // $ 2 = SEND|RECV|POLL|PAGE
record.fput("\t%s", commid); // $ 3 = commid
record.fput("\t%s", device); // $ 4 = device
record.fput("\t%s", jobid); // $ 5 = jobid
- u_int i = 0;
- char c;
- for (const char* cp = jobtag; (c = *cp); cp++) {
- if (i == sizeof (buf)-2) // truncate string
- break;
- if (c == '\t') // tabs are field delimiters
- c = ' ';
- else if (c == '"') // escape quote marks
- buf[i++] = '\\';
- buf[i++] = c;
- }
- buf[i] = '\0';
- record.fput("\t\"%s\"", buf); // $ 6 = jobtag
+ record.fput("\t\"%s\"", jobtagbuf); // $ 6 = jobtag
record.fput("\t%s", user); // $ 7 = sender
record.fput("\t\"%s\"", dest); // $ 8 = dest
record.fput("\t\"%s\"", csi); // $ 9 = csi
@@ -72,11 +87,6 @@
record.fput("\t\"%s\"", status); // $14 = status
record.fput("\t\"%s\"", callid.size() > CallID::NAME ? (const char*) callid[1] : ""); // $15 = CallID2/CIDName
record.fput("\t\"%s\"", callid.size() > CallID::NUMBER ? (const char*) callid[0] : ""); // $16 = CallID1/CIDNumber
- fxStr callid_formatted = "";
- for (i = 2; i < callid.size(); i++) {
- if (i > 2) callid_formatted.append("::");
- callid_formatted.append(callid[i]);
- }
record.fput("\t\"%s\"", (const char*) callid_formatted); // $17 = CallID3 -> CallIDn
record.fput("\t\"%s\"", owner); // $18 = owner
record.fput("\t\"%s\"", (const char*) faxdcs); // $19 = DCS
@@ -85,5 +95,44 @@
ok = (Sys::write(fd, record, record.getLength()) == (ssize_t)record.getLength());
Sys::close(fd); // implicit unlock
}
+
+ /*
+ * Here we provide a hook for an external accounting
+ * facility, such as a database.
+ */
+ const char* argv[21];
+ argv[0] = "FaxAccounting";
+ argv[1] = timebuf;
+ argv[2] = cmd;
+ argv[3] = commid;
+ argv[4] = device;
+ argv[5] = jobid;
+ argv[6] = jobtagbuf;
+ argv[7] = user;
+ argv[8] = dest;
+ argv[9] = csi;
+ argv[10] = (const char*) paramsbuf;
+ argv[11] = (const char*) npagesbuf;
+ argv[12] = (const char*) durationbuf;
+ argv[13] = (const char*) conntimebuf;
+ argv[14] = status;
+ argv[15] = callid.size() > CallID::NAME ? (const char*) callid[1] : "";
+ argv[16] = callid.size() > CallID::NUMBER ? (const char*) callid[0] : "";
+ argv[17] = (const char*) callid_formatted;
+ argv[18] = owner;
+ argv[19] = (const char*) faxdcs;
+ argv[20] = NULL;
+ pid_t pid = fork(); // signal handling in some apps seems to require a fork here
+ switch (pid) {
+ case 0:
+ Sys::execv("etc/FaxAccounting", (char* const*) argv);
+ sleep(1); // XXX give parent time
+ _exit(127);
+ case -1:
+ break;
+ default:
+ Sys::waitpid(pid);
+ break;
+ }
return (ok);
}
diff -Nru hylafax.orig/faxd/faxQueueApp.c++ hylafax/faxd/faxQueueApp.c++
--- hylafax.orig/faxd/faxQueueApp.c++ 2005-11-14 08:33:31.000000000 -0800
+++ hylafax/faxd/faxQueueApp.c++ 2005-11-15 15:02:17.523374808 -0800
@@ -1982,7 +1982,7 @@
}
void
-faxQueueApp::timeoutAccounting(Job& job, FaxRequest& req)
+faxQueueApp::queueAccounting(Job& job, FaxRequest& req, const char* type)
{
FaxAcctInfo ai;
ai.jobid = (const char*) req.jobid;
@@ -1997,7 +1997,11 @@
ai.csi = "";
ai.npages = 0;
ai.params = 0;
- ai.status = "Kill time expired";
+ ai.status = "";
+ if (strstr(type, "UNSENT"))
+ ai.status = "Kill time expired";
+ else if (strstr(type, "SUBMIT"));
+ ai.status = "Submitted";
CallID empty_callid;
ai.callid = empty_callid;
ai.owner = (const char*) req.owner;
@@ -2005,14 +2009,14 @@
pid_t pid = fork();
switch (pid) {
case -1: // error
- if (!ai.record("UNSENT"))
- logError("Error writing UNSENT accounting record, dest=%s",
- (const char*) ai.dest);
+ if (!ai.record(type))
+ logError("Error writing %s accounting record, dest=%s",
+ type, (const char*) ai.dest);
break;
case 0: // child
- if (!ai.record("UNSENT"))
+ if (!ai.record(type))
logError("Error writing UNSENT accounting record, dest=%s",
- (const char*) ai.dest);
+ type, (const char*) ai.dest);
_exit(255);
/*NOTREACHED*/
default: // parent
@@ -2037,7 +2041,7 @@
job.state = FaxRequest::state_failed;
FaxRequest* req = readRequest(job);
if (req) {
- timeoutAccounting(job, *req);
+ queueAccounting(job, *req, "UNSENT");
req->notice = "Kill time expired";
deleteRequest(job, req, Job::timedout, true);
}
@@ -2062,7 +2066,7 @@
job.state = FaxRequest::state_failed;
traceQueue(job, "KILL TIME EXPIRED");
Trigger::post(Trigger::JOB_TIMEDOUT, job);
- timeoutAccounting(job, req);
+ queueAccounting(job, req, "UNSENT");
req.notice = "Kill time expired";
deleteRequest(job, req, Job::timedout, true);
setDead(job);
@@ -2073,7 +2077,7 @@
* using the specified job description file.
*/
bool
-faxQueueApp::submitJob(const fxStr& jobid, bool checkState)
+faxQueueApp::submitJob(const fxStr& jobid, bool checkState, bool doaccounting)
{
Job* job = Job::getJobByID(jobid);
if (job) {
@@ -2127,6 +2131,7 @@
req.state != FaxRequest::state_done &&
req.state != FaxRequest::state_failed) {
status = submitJob(req, checkState);
+ if (doaccounting) queueAccounting(*job, req, "SUBMIT");
} else if (reject) {
Job job(req);
job.state = FaxRequest::state_failed;
@@ -2788,7 +2793,7 @@
break;
case 'S': // submit an outbound job
traceServer("SUBMIT JOB %s", args);
- if (status = submitJob(args))
+ if (status = submitJob(args, false, true))
pokeScheduler();
break;
case 'U': // unreference file
diff -Nru hylafax.orig/faxd/faxQueueApp.h hylafax/faxd/faxQueueApp.h
--- hylafax.orig/faxd/faxQueueApp.h 2005-11-14 08:33:31.000000000 -0800
+++ hylafax/faxd/faxQueueApp.h 2005-11-15 15:02:38.742149064 -0800
@@ -204,7 +204,7 @@
void blockJob(Job&, FaxRequest&, const char*);
void delayJob(Job&, FaxRequest&, const char*, time_t);
void rejectJob(Job& job, FaxRequest& req, const fxStr& reason);
- bool submitJob(const fxStr& jobid, bool checkState = false);
+ bool submitJob(const fxStr& jobid, bool checkState = false, bool doaccounting = false);
bool suspendJob(const fxStr& jobid, bool abortActive);
void rejectSubmission(Job&, FaxRequest&, const fxStr& reason);
@@ -217,7 +217,7 @@
bool submitJob(Job& job, FaxRequest& req, bool checkState = false);
bool suspendJob(Job& job, bool abortActive);
bool terminateJob(const fxStr& filename, JobStatus why);
- void timeoutAccounting(Job& job, FaxRequest&);
+ void queueAccounting(Job& job, FaxRequest&, const char* type);
void timeoutJob(Job& job);
void timeoutJob(Job& job, FaxRequest&);
void runJob(Job& job);
diff -Nru hylafax.orig/man/wedged.1m hylafax/man/wedged.1m
--- hylafax.orig/man/wedged.1m 2005-11-14 08:33:31.000000000 -0800
+++ hylafax/man/wedged.1m 2005-11-15 14:23:30.365156632 -0800
@@ -74,7 +74,8 @@
.P
If there exists an executable file
.B ${SPOOL}/etc/resetmodem
-then that file will be executed upon execution of
+then that file will be executed (with the device name as the only
+argument) upon execution of
the
.I wedged
script in an effort to recover the modem.
diff -Nru hylafax.orig/man/xferfaxlog.4f hylafax/man/xferfaxlog.4f
--- hylafax.orig/man/xferfaxlog.4f 2005-11-14 08:33:31.000000000 -0800
+++ hylafax/man/xferfaxlog.4f 2005-11-15 14:54:08.502717248 -0800
@@ -34,9 +34,11 @@
The file
.B etc/xferfaxlog
contains information about inbound and outbound activities.
-The file contains one line per inbound or outbound call
-(except for facsimile documents retrieved by polling in which
-case multiple entries may be present for a single call).
+The file contains one line per inbound facsimile document or outbound job.
+The file also contains one line per expired job and one line per job submitted.
+If the modem config setting
+.I LogCalls
+is set to true, then the file also contains one line per received call.
Lines are fixed-format,
.I tab-separated
.SM ASCII
@@ -44,13 +46,19 @@
Each record of a facsimile transmission is of the form:
.sp .5
.ti +0.5i
-date \s-1SEND\s+1 commid modem jobid jobtag sender ``dest-number'' ``\s-1CSI\s+1'' params #pages jobtime conntime ``reason'' \fI<null>\fP \fI<null>\fP ``owner''
+date \s-1SEND\s+1 commid modem jobid jobtag sender ``dest-number'' ``\s-1CSI\s+1'' params #pages jobtime conntime ``reason'' \fI<null>\fP \fI<null>\fP ``owner'' ``dcs''
.sp .5
.PP
-A facsimile reception record is of the form:
+A facsimile document reception record is of the form:
.sp .5
.ti +0.5i
-date \s-1RECV\s+1 commid modem \fI<null>\fP \fI<null>\fP fax ``local-number'' ``\s-1TSI\s+1'' params #pages jobtime conntime ``reason'' ``CIDName'' ``CIDNumber'' \fI<null>\fP
+date \s-1RECV\s+1 commid modem \fI<null>\fP \fI<null>\fP fax ``local-number'' ``\s-1TSI\s+1'' params #pages jobtime conntime ``reason'' ``CIDName'' ``CIDNumber'' ``callid'' \fI<null>\fP ``dcs''
+.sp .5
+.PP
+Call records are of the form:
+.sp .5
+.ti +0.5i
+date \s-1CALL\s+1 commid modem \fI<null>\fP \fI<null>\fP fax ``local-number'' ``\s-1<null>\s+1'' 0 0 jobtime conntime ``\s-1<null>\s+1'' ``CIDName'' ``CIDNumber'' ``callid'' ....
.sp .5
.PP
Each facsimile document retrieved by polling has a record of the form:
@@ -58,12 +66,23 @@
.ti +0.5i
date \s-1POLL\s+1 commid modem jobid jobtag sender ``dest-number'' ``\s-1TSI\s+1'' params #pages jobtime conntime ``reason'' \fI<null>\fP \fI<null>\fP \fI<null>\fP
.sp .5
+.PP
An alphanumeric pager request has a record of the form:
.sp .5
.ti +0.5i
date \s-1PAGE\s+1 commid modem jobid jobtag sender ``dest-number'' ``\fI<null>\fP'' 0 0 jobtime conntime ``reason'' \fI<null>\fP \fI<null>\fP ``owner''
.sp .5
.PP
+Expired job records are of the form:
+.sp .5
+.ti +0.5i
+date \s-1UNSENT\s+1 ``\fI<null>\fP'' ``\fI<null>\fP'' jobid ....
+.PP
+Job submission records are of the form:
+.sp .5
+.ti +0.5i
+date \s-1SUBMIT\s+1 ``\fI<null>\fP'' ``\fI<null>\fP'' jobid ....
+.PP
The following describes the fields in the above records:
.TP 14
.B date
@@ -138,6 +157,12 @@
.TP 14
.B owner
The login name of the job owner.
+.TP 14
+.B callid
+The CallID values other than CIDName and CIDNumber formatted by ``::'' delimeters.
+.TP 14
+.B dcs
+The T.30 DCS string that was used in the facsimile communication.
.PP
Note that fields may have embedded blanks.
Session parameters are encoded as a decimal number that contains
@@ -153,13 +178,23 @@
.SM ASCII
format was designed to be easy to process with programs like
.IR awk (1).
+.PP
+If an executable named
+.B ${SPOOL}/etc/FaxAccounting
+exists then it will be executed every time a record is written to
+.B etc/xferfaxlog.
+The record fields will each serve as separate command arguments.
+This is designed to allow attachment to external databases and other
+accounting mechanisms.
.SH NOTES
The sender field does not necessarily represent the submitter's
actual identity. For example, it reflects the value given by
the
.IR sendfax (${MANNUM1_8})
``-f'' option. Be cautious that this field is not utilized
-for auditing if the fax user base is not trusted.
+for auditing if the fax user base is not trusted. Use
+.IR owner
+instead, if possible.
.SH BUGS
The date format will ``break'' in the year 2000.
Information should be recorded on a per-page basis for facsimile