Ideally, the storage backends should provide a robust journaling, logging and crash-recovery mechanism. But just in case they don't, or it didn't work, this mechanism provides a "Plan B" by providing a low-tech, fool-proof, simple logging system that can be used to recover user input. There are some simple command-line tools that will read a log and replay it.
Files | |
| file | TransLog.h |
| API for the transaction logger. | |
Functions | |
| void | xaccOpenLog (void) |
| void | xaccCloseLog (void) |
| void | xaccReopenLog (void) |
| void | xaccTransWriteLog (Transaction *trans, char flag) |
| void | xaccLogEnable (void) |
| void | xaccLogDisable (void) |
| void | xaccLogSetBaseName (const char *) |
| gboolean | xaccFileIsCurrentLog (const gchar *name) |
| gboolean xaccFileIsCurrentLog | ( | const gchar * | name | ) |
Test a filename to see if it is the name of the current logfile
Definition at line 126 of file TransLog.c.
00127 { 00128 gchar *base; 00129 gint result; 00130 00131 if (!name || !trans_log_name) 00132 return FALSE; 00133 00134 base = g_path_get_basename(name); 00135 result = (strcmp(base, trans_log_name) == 0); 00136 g_free(base); 00137 return result; 00138 }
| void xaccLogDisable | ( | void | ) |
| void xaccLogEnable | ( | void | ) |
| void xaccLogSetBaseName | ( | const char * | ) |
The xaccLogSetBaseName() method sets the base filepath and the root part of the journal file name. If the journal file is already open, it will close it and reopen it with the new base name.
Definition at line 105 of file TransLog.c.
00106 { 00107 if (!basepath) return; 00108 00109 g_free (log_base_name); 00110 log_base_name = g_strdup (basepath); 00111 00112 if (trans_log) { 00113 xaccCloseLog(); 00114 xaccOpenLog(); 00115 } 00116 }
| void xaccTransWriteLog | ( | Transaction * | trans, | |
| char | flag | |||
| ) |
| trans | The transaction to write out to the log | |
| flag | The engine currently uses the log mechanism with flag char set as follows: 'B' for 'begin edit' (followed by the transaction as it looks before any changes, i.e. the 'old value') 'D' for delete (i.e. delete the previous B; echoes the data in the 'old B') 'C' for commit (i.e. accept a previous B; data that follows is the 'new value') 'R' for rollback (i.e. revert to previous B; data that follows should be identical to old B) |
Definition at line 203 of file TransLog.c.
00204 { 00205 GList *node; 00206 char trans_guid_str[GUID_ENCODING_LENGTH+1]; 00207 char split_guid_str[GUID_ENCODING_LENGTH+1]; 00208 const char *trans_notes; 00209 char dnow[100], dent[100], dpost[100], drecn[100]; 00210 Timespec ts; 00211 00212 if (!gen_logs) return; 00213 if (!trans_log) return; 00214 00215 timespecFromTime_t(&ts,time(NULL)); 00216 gnc_timespec_to_iso8601_buff (ts, dnow); 00217 00218 timespecFromTime_t(&ts,trans->date_entered.tv_sec); 00219 gnc_timespec_to_iso8601_buff (ts, dent); 00220 00221 timespecFromTime_t(&ts,trans->date_posted.tv_sec); 00222 gnc_timespec_to_iso8601_buff (ts, dpost); 00223 00224 guid_to_string_buff (xaccTransGetGUID(trans), trans_guid_str); 00225 trans_notes = xaccTransGetNotes(trans); 00226 fprintf (trans_log, "===== START\n"); 00227 00228 for (node = trans->splits; node; node = node->next) 00229 { 00230 Split *split = node->data; 00231 const char * accname = ""; 00232 char acc_guid_str[GUID_ENCODING_LENGTH+1]; 00233 gnc_numeric amt,val; 00234 00235 if (xaccSplitGetAccount(split)) 00236 { 00237 accname = xaccAccountGetName (xaccSplitGetAccount(split)); 00238 guid_to_string_buff(xaccAccountGetGUID(xaccSplitGetAccount(split)), 00239 acc_guid_str); 00240 } 00241 else 00242 { 00243 acc_guid_str[0] = '\0'; 00244 } 00245 00246 timespecFromTime_t(&ts,split->date_reconciled.tv_sec); 00247 gnc_timespec_to_iso8601_buff (ts, drecn); 00248 00249 guid_to_string_buff (xaccSplitGetGUID(split), split_guid_str); 00250 amt = xaccSplitGetAmount (split); 00251 val = xaccSplitGetValue (split); 00252 00253 /* use tab-separated fields */ 00254 fprintf (trans_log, 00255 "%c\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t" 00256 "%s\t%s\t%s\t%s\t%c\t%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT "\t%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT "\t%s\n", 00257 flag, 00258 trans_guid_str, split_guid_str, /* trans+split make up unique id */ 00259 /* Note that the next three strings always exist, 00260 * so we don't need to test them. */ 00261 dnow, 00262 dent, 00263 dpost, 00264 acc_guid_str, 00265 accname ? accname : "", 00266 trans->num ? trans->num : "", 00267 trans->description ? trans->description : "", 00268 trans_notes ? trans_notes : "", 00269 split->memo ? split->memo : "", 00270 split->action ? split->action : "", 00271 split->reconciled, 00272 gnc_numeric_num(amt), 00273 gnc_numeric_denom(amt), 00274 gnc_numeric_num(val), 00275 gnc_numeric_denom(val), 00276 /* The next string always exists. No need to test it. */ 00277 drecn); 00278 } 00279 00280 fprintf (trans_log, "===== END\n"); 00281 00282 /* get data out to the disk */ 00283 fflush (trans_log); 00284 }
1.5.2