annotate eventLogger.mm @ 0:a223551fdc1f

First commit - copy from tweakathlon.
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Fri, 10 Oct 2014 11:46:42 +0100
parents
children 36cdb73691da
rev   line source
rt300@0 1 //
rt300@0 2 // eventLogger.mm
rt300@0 3 // oscSenderExample
rt300@0 4 //
rt300@0 5 // Created by Robert Tubb on 05/11/2012.
rt300@0 6 //
rt300@0 7 //
rt300@0 8
rt300@0 9 //---------------------------------------------------------------------------
rt300@0 10 #include "eventLogger.h"
rt300@0 11
rt300@0 12 EventLogger eventLogger;
rt300@0 13
rt300@0 14 //---------------------------------------------------------------------------
rt300@0 15 EventLogger::EventLogger(){
rt300@0 16
rt300@0 17 consentGiven = true; // unless told otherwise firstAppOpen
rt300@0 18 loggingEnabled = true;
rt300@0 19 serverConnectionOK = false;
rt300@0 20 questionnaireCompleted = false;
rt300@0 21 questionnaireUploaded = false;
rt300@0 22 logUploadInProgress = false;
rt300@0 23
rt300@0 24 nextUploadQty = UPLOAD_CHUNK_SIZE; // amount of data uploaded is always more than UPLOAD_CHUNK_SIZE events
rt300@0 25 serverComms = [[ServerComms alloc] init];
rt300@0 26
rt300@0 27 }
rt300@0 28 //---------------------------------------------------------------------------
rt300@0 29 void EventLogger::startLoadAll(){
rt300@0 30
rt300@0 31 // TODO pilot doesn't check existing
rt300@0 32 //loadExistingLogFile(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME);
rt300@0 33
rt300@0 34
rt300@0 35 sessionStartTime = ofGetSystemTime();
rt300@0 36
rt300@0 37 // TODO pilot
rt300@0 38 // testConnection();
rt300@0 39
rt300@0 40 // if we have a back log of events upload them
rt300@0 41 if(theEvents.size() > nextUploadQty && ! logUploadInProgress){
rt300@0 42 //try to upload
rt300@0 43
rt300@0 44 // TODO pilot doesn't upload
rt300@0 45 //uploadEventLog(true);
rt300@0 46 }
rt300@0 47
rt300@0 48 if(questionnaireCompleted && !questionnaireUploaded){
rt300@0 49 uploadQuestionnaire();
rt300@0 50 }
rt300@0 51
rt300@0 52 //TODO if questionnaire wasn't reached but still opened then set the timer to something sensible
rt300@0 53
rt300@0 54 //timer.setInteractionTime(savedInteractionTime);
rt300@0 55 //timer.setOrderFromPrevious(interfaceOrder);
rt300@0 56
rt300@0 57 // for now sod it, start from scratch
rt300@0 58 if(!questionnaireCompleted){
rt300@0 59 cout<<"Questionnaire NOT completed - first APP open called\n";
rt300@0 60 firstEverAppOpen();
rt300@0 61 }
rt300@0 62
rt300@0 63 }
rt300@0 64 //---------------------------------------------------------------------------
rt300@0 65 void EventLogger::testConnection(){
rt300@0 66 Json::Value root;
rt300@0 67 root["x"] = "y";
rt300@0 68 cout << "testConnection\n";
rt300@0 69 sendToServer("testConnection", root, true);
rt300@0 70
rt300@0 71 }
rt300@0 72 //---------------------------------------------------------------------------
rt300@0 73 // this reads the persistent log file , checks if we've used the app before and
rt300@0 74 // if we've answered questionnaire or not
rt300@0 75
rt300@0 76 // should just store stuff. the start up state should be handled by testAPp
rt300@0 77
rt300@0 78 void EventLogger::loadExistingLogFile(const string &jsonFile){
rt300@0 79 Json::Value root;
rt300@0 80 Json::Reader reader;
rt300@0 81
rt300@0 82 /////////////
rt300@0 83 // read file
rt300@0 84
rt300@0 85 ifstream theFile(jsonFile.c_str());
rt300@0 86 stringstream fileText;
rt300@0 87 string line;
rt300@0 88 if(!theFile){
rt300@0 89 cout<<"No event log file found - first APP open called\n";
rt300@0 90 firstEverAppOpen();
rt300@0 91 return;
rt300@0 92 }else{
rt300@0 93 while(theFile){
rt300@0 94 theFile >> line;
rt300@0 95 // cout << line; // lots!!!!
rt300@0 96 fileText << line;
rt300@0 97 }
rt300@0 98 theFile.close();
rt300@0 99 }
rt300@0 100
rt300@0 101 cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n";
rt300@0 102
rt300@0 103 bool parsingSuccessful = reader.parse( fileText.str(), root );
rt300@0 104
rt300@0 105 if ( !parsingSuccessful )
rt300@0 106 {
rt300@0 107 // report to the user the failure and their locations in the document.
rt300@0 108 std::cout << "Failed to parse event log JSON: \n"
rt300@0 109 << reader.getFormattedErrorMessages();
rt300@0 110 return;
rt300@0 111 }
rt300@0 112
rt300@0 113 /////////////////
rt300@0 114 // now put user deets into variables
rt300@0 115
rt300@0 116 userName = root["userName"].asString();
rt300@0 117 deviceID = root["deviceID"].asLargestInt();
rt300@0 118 nextUploadNumber = root["uploadNumber"].asInt();
rt300@0 119 savedInteractionTime = root["savedInteractionTime"].asLargestInt();
rt300@0 120 questionnaireCompleted = root["questionnaireCompleted"].asBool();
rt300@0 121 questionnaireUploaded = root["questionnaireUploaded"].asBool();
rt300@0 122
rt300@0 123 // check for unuploaded evts
rt300@0 124 const Json::Value jlogs = root["events"];
rt300@0 125
rt300@0 126 for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index]));
rt300@0 127
rt300@0 128
rt300@0 129 //////////////
rt300@0 130
rt300@0 131 if(questionnaireCompleted && !questionnaireUploaded){
rt300@0 132 // then read it in and upload it
rt300@0 133 Json::Value JQ = root["questionnaire"];
rt300@0 134 Json::Value JArray = JQ["qAnswers"];
rt300@0 135 if(JArray.size() < 2){
rt300@0 136 cout << "Error - status of questionnaire is wierd\n";
rt300@0 137 }
rt300@0 138 for ( unsigned int i = 0; i < JArray.size(); i++ )
rt300@0 139 {
rt300@0 140 questionnaireAnswers.push_back(JArray[i].asInt());
rt300@0 141 }
rt300@0 142 questionnaireComments = JQ["comments"].toStyledString();
rt300@0 143 //uploadQuestionnaire();
rt300@0 144 }
rt300@0 145
rt300@0 146 // TODO interaction time seems to be balls
rt300@0 147 cout << "Total interaction time: " << savedInteractionTime << '\n';
rt300@0 148
rt300@0 149 }
rt300@0 150
rt300@0 151 //---------------------------------------------------------------------------
rt300@0 152
rt300@0 153 void EventLogger::firstEverAppOpen(){
rt300@0 154
rt300@0 155 nextUploadNumber = 0;
rt300@0 156 deviceID = ofGetSystemTimeMicros();
rt300@0 157 savedInteractionTime = 0;
rt300@0 158 questionnaireCompleted = false;
rt300@0 159 questionnaireUploaded = false;
rt300@0 160
rt300@0 161 }
rt300@0 162
rt300@0 163
rt300@0 164 //---------------------------------------------------------------------------
rt300@0 165 void EventLogger::questionnaireAnswersObtained(vector<int> answers, const char* userComments){
rt300@0 166
rt300@0 167 questionnaireCompleted = true;
rt300@0 168 questionnaireAnswers = answers;
rt300@0 169 questionnaireComments = userComments;
rt300@0 170 uploadQuestionnaire();
rt300@0 171 logEvent(QUESTIONNAIRE_COMPLETED);
rt300@0 172
rt300@0 173 }
rt300@0 174 //---------------------------------------------------------------------------
rt300@0 175 void EventLogger::uploadQuestionnaire(){
rt300@0 176 // show indicator
rt300@0 177 cout << "^^^^^^^^ UPLOADING QUESTIONNAIRE ^^^^^^^^ \n";
rt300@0 178 cout << questionnaireToJson() << "\n";
rt300@0 179 sendToServer("questionnaire", questionnaireToJson(), true);
rt300@0 180
rt300@0 181 }
rt300@0 182 //---------------------------------------------------------------------------
rt300@0 183 bool EventLogger::sendToServer(string functionName, Json::Value jsonData, bool async = false){
rt300@0 184
rt300@0 185 Json::FastWriter writer;
rt300@0 186 string jsontext = writer.write( jsonData );
rt300@0 187
rt300@0 188 // remove newline
rt300@0 189 if (!jsontext.empty() && jsontext[jsontext.length()-1] == '\n') {
rt300@0 190 jsontext.erase(jsontext.length()-1);
rt300@0 191 }
rt300@0 192 ostringstream jd;
rt300@0 193 jd << jsontext;
rt300@0 194 NSString *theData = [NSString stringWithUTF8String:jd.str().c_str()];
rt300@0 195 NSString *theType = [NSString stringWithUTF8String:functionName.c_str()];
rt300@0 196
rt300@0 197 if(async){
rt300@0 198 [serverComms doPostRequest:theType withData:theData];
rt300@0 199 }else{
rt300@0 200 bool success = [serverComms doSyncPostRequest:theType withData:theData];
rt300@0 201 return success;
rt300@0 202 }
rt300@0 203
rt300@0 204 }
rt300@0 205 //-----------------------------
rt300@0 206 void EventLogger::questionnaireOK(){
rt300@0 207 questionnaireUploaded = true;
rt300@0 208 questionnaireComments = "";
rt300@0 209 }
rt300@0 210 //-----------------------------
rt300@0 211 void EventLogger::eventlogOK(){
rt300@0 212 // COMMENT THIS IF UPLAODING FROM IPAD TO XCODE
rt300@0 213
rt300@0 214 // it's a bad idea to do this in another thread...
rt300@0 215 theEvents.clear();
rt300@0 216 cout << "EVENT LOG UPLOAD SUCCESS\n";
rt300@0 217 nextUploadNumber++;
rt300@0 218 logUploadInProgress = false;
rt300@0 219 }
rt300@0 220 //-----------------------------
rt300@0 221 void EventLogger::testConnectionOK(){
rt300@0 222 cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n";
rt300@0 223 serverConnectionOK = true;
rt300@0 224 }
rt300@0 225 //-----------------------------
rt300@0 226 void EventLogger::questionnaireNotOK(){
rt300@0 227 cout << "XXXXX questionnaire NOT OK XXXXXXX \n";
rt300@0 228 questionnaireUploaded = false;
rt300@0 229 }
rt300@0 230 //-----------------------------
rt300@0 231 void EventLogger::eventlogNotOK(){
rt300@0 232 // try later
rt300@0 233 cout << "XXXXX event log NOT OK XXXXXXX \n";
rt300@0 234 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@0 235 logUploadInProgress = false;
rt300@0 236 }
rt300@0 237 //-----------------------------
rt300@0 238 void EventLogger::testConnectionNotOK(){
rt300@0 239 cout << "XXXXX server connection NOT OK XXXXXXX \n";
rt300@0 240 serverConnectionOK = false;
rt300@0 241 // alert?
rt300@0 242
rt300@0 243 }
rt300@0 244
rt300@0 245
rt300@0 246 //---------------------------------------------------------------------------
rt300@0 247
rt300@0 248 bool EventLogger::uploadEventLog(bool async){
rt300@0 249
rt300@0 250 // show indicator
rt300@0 251 logUploadInProgress = true;
rt300@0 252 cout << "^^^^^^^^ ATTEMPTING TO UPLOAD " << theEvents.size() << " EVENTS ^^^^^^^^ .\n";
rt300@0 253 if(!async){
rt300@0 254 bool success = sendToServer("eventlog", logsToJson(), async);
rt300@0 255 if(!success){
rt300@0 256 // try later
rt300@0 257 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@0 258 // increment upload number?
rt300@0 259 }else{
rt300@0 260
rt300@0 261 // if success - clear memory
rt300@0 262 // IF UPLAODING FROM IPAD TO XCODE COMMENT OUT
rt300@0 263 theEvents.clear();
rt300@0 264 cout << "UPLOAD SUCCESS\n";
rt300@0 265 nextUploadNumber++;
rt300@0 266 }
rt300@0 267 logUploadInProgress = false;
rt300@0 268 return success;
rt300@0 269 }else{
rt300@0 270 sendToServer("eventlog", logsToJson(), async);
rt300@0 271 }
rt300@0 272 }
rt300@0 273 //---------------------------------------------------------------------------
rt300@0 274 // only called when doing supervised tests
rt300@0 275 void EventLogger::newUser(){
rt300@0 276 // store old stuff
rt300@0 277
rt300@0 278 saveSessionToFile();
rt300@0 279 cout<<"setup new user\n";
rt300@0 280 deleteLogs();
rt300@0 281 nextUploadNumber = 0;
rt300@0 282 deviceID = ofGetSystemTimeMicros();
rt300@0 283 savedInteractionTime = 0;
rt300@0 284 totalInteractionTime = 0;
rt300@0 285 sessionStartTime = ofGetSystemTime();
rt300@0 286 questionnaireCompleted = false;
rt300@0 287 questionnaireUploaded = false;
rt300@0 288
rt300@0 289 //((testApp *)ofGetAppPtr())->showIntro();
rt300@0 290
rt300@0 291 }
rt300@0 292 //---------------------------------------------------------------------------
rt300@0 293 // called from alertView OK in iViewController
rt300@0 294 void EventLogger::setUsername(const char *u){
rt300@0 295 userName = u;
rt300@0 296
rt300@0 297 }
rt300@0 298 //---------------------------------------------------------------------------
rt300@0 299 //new tweakathlon event logger with vector
rt300@0 300 void EventLogger::logEvent(const leventType& evtType, const vector<int> eventData){
rt300@0 301 Poco::Mutex::ScopedLock lock(_mutex);
rt300@0 302 if(!loggingEnabled) return;
rt300@0 303
rt300@0 304 switch ( evtType ) {
rt300@0 305
rt300@0 306 // case CANDIDATE_PARAM_ADJUSTED:
rt300@0 307 // // TODO thinning here. maybe. was a pain in the butt.
rt300@0 308 // thinnedSliderEvent(lEvent(evtType,eventData));
rt300@0 309 // break;
rt300@0 310 default:
rt300@0 311 // default is just an event type with vector of ints. matlab will know what they are.
rt300@0 312
rt300@0 313
rt300@0 314 theEvents.push_back(lEvent(evtType, eventData));
rt300@0 315
rt300@0 316 break;
rt300@0 317 }
rt300@0 318
rt300@0 319 if(theEvents.size() > nextUploadQty && !logUploadInProgress){
rt300@0 320 //try to upload asynchronously
rt300@0 321 // TODO pilot doesn't upload
rt300@0 322 //uploadEventLog(true);
rt300@0 323 }
rt300@0 324 //TODO thiswrong?
rt300@0 325 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds
rt300@0 326
rt300@0 327 }
rt300@0 328 //---------------------------------------------------------------------------
rt300@0 329 // OLD SONIC ZOOM EVT - still used for simple events with no data
rt300@0 330 void EventLogger::logEvent(const leventType& evtType){
rt300@0 331 Poco::Mutex::ScopedLock lock(_mutex);
rt300@0 332 if(!loggingEnabled) return;
rt300@0 333
rt300@0 334 switch ( evtType ) {
rt300@0 335 // data thinning here
rt300@0 336 case APP_LOADED:
rt300@0 337 theEvents.push_back(lEvent(evtType));
rt300@0 338 default:
rt300@0 339 // default is just an event type with vector of ints. matlab will know what they are.
rt300@0 340
rt300@0 341
rt300@0 342 theEvents.push_back(lEvent(evtType));
rt300@0 343
rt300@0 344 }
rt300@0 345
rt300@0 346 if(theEvents.size() > nextUploadQty && !logUploadInProgress){
rt300@0 347 //try to upload asynchronously
rt300@0 348 // TODO pilot doesn't upload
rt300@0 349 //uploadEventLog(true);
rt300@0 350 }
rt300@0 351 //TODO thiswrong?
rt300@0 352 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds
rt300@0 353
rt300@0 354 }
rt300@0 355 // UnaryPredicate
rt300@0 356 template <class T>
rt300@0 357 bool EventLogger::matchID(T thing){
rt300@0 358 return true;
rt300@0 359 }
rt300@0 360 bool EventLogger::matchID2(){
rt300@0 361 return true;
rt300@0 362 }
rt300@0 363 //---------------------------------------------------------------------------
rt300@0 364 void EventLogger::thinnedSliderEvent(lEvent newEvent){
rt300@0 365 static vector<lEvent> unloggedEventsCache; // list of all different slider events
rt300@0 366 static int eventCounter = 0;
rt300@0 367
rt300@0 368 // if first event then log it.
rt300@0 369 if(theEvents.size() == 0){
rt300@0 370 theEvents.push_back(newEvent);
rt300@0 371 }
rt300@0 372
rt300@0 373 // look for last event in the cache that had this mappingID
rt300@0 374 cout << unloggedEventsCache.size() << endl;
rt300@0 375
rt300@0 376 vector<lEvent>::iterator lastMatching;
rt300@0 377 for(lastMatching = unloggedEventsCache.begin();
rt300@0 378 lastMatching != unloggedEventsCache.end() && ( (*lastMatching).eventData[0] != newEvent.eventData[0]);
rt300@0 379 lastMatching++);
rt300@0 380
rt300@0 381
rt300@0 382 if (lastMatching != unloggedEventsCache.end()){
rt300@0 383 //cout << "matching id logevent: " << (*lastMatching).eventData[0] << " " << newEvent.eventData[0] << endl;
rt300@0 384 // we have another, check gap
rt300@0 385 int gap = newEvent.eventTime - (*lastMatching).eventTime;
rt300@0 386 if(gap > 300){
rt300@0 387 theEvents.push_back((*lastMatching));
rt300@0 388
rt300@0 389 // also log new slider evt
rt300@0 390 theEvents.push_back(newEvent);
rt300@0 391 eventCounter = 0;
rt300@0 392
rt300@0 393 }else if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event
rt300@0 394 theEvents.push_back(newEvent);
rt300@0 395 eventCounter = 0;
rt300@0 396 // DELETE THAT PREVIOUS EVENT
rt300@0 397 unloggedEventsCache.erase(lastMatching);
rt300@0 398
rt300@0 399 }else{
rt300@0 400 // ignore for now but put in unlogged
rt300@0 401 unloggedEventsCache.push_back(newEvent);
rt300@0 402 }
rt300@0 403
rt300@0 404 }else{
rt300@0 405 // this event type wasnt in the cache
rt300@0 406 if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event
rt300@0 407 theEvents.push_back(newEvent);
rt300@0 408 eventCounter = 0;
rt300@0 409 }else{
rt300@0 410 unloggedEventsCache.push_back(newEvent);
rt300@0 411 }
rt300@0 412
rt300@0 413 }
rt300@0 414 // always count the new one
rt300@0 415 eventCounter++;
rt300@0 416
rt300@0 417
rt300@0 418
rt300@0 419 }
rt300@0 420
rt300@0 421 //--------------------------------------------------------------------
rt300@0 422 // called from newUser
rt300@0 423 void EventLogger::deleteLogs(){
rt300@0 424 // the
rt300@0 425 theEvents.clear();
rt300@0 426 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@0 427 ofFile logFile(fname,ofFile::WriteOnly);
rt300@0 428 logFile << "";
rt300@0 429 logFile.close();
rt300@0 430 }
rt300@0 431 //---------------------------------------------------------------------------
rt300@0 432
rt300@0 433 void EventLogger::exitAndSave(){
rt300@0 434
rt300@0 435 if(!consentGiven){
rt300@0 436 Json::Value jlogs = logsToJson();
rt300@0 437 // try to upload TODO (no - might hang and prevent exit???)
rt300@0 438
rt300@0 439 // TODO pilot doesn't upload
rt300@0 440 // uploadEventLog(true);
rt300@0 441 return;
rt300@0 442 }
rt300@0 443
rt300@0 444 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@0 445 // save user details
rt300@0 446 string fname = ofxiPhoneGetDocumentsDirectory() + userName + '_' + EVENT_LOG_FILENAME;
rt300@0 447
rt300@0 448 // try to upload
rt300@0 449 // do it sync because event list needs to be cleared to prevent saving on device
rt300@0 450
rt300@0 451 // TODO for pilot store to ipad
rt300@0 452 // uploadEventLog(false);
rt300@0 453
rt300@0 454 // write to file
rt300@0 455 // json without the logs that were uploaded!
rt300@0 456 Json::Value jlogs = logsToJson();
rt300@0 457 ofFile logFile(fname,ofFile::WriteOnly);
rt300@0 458 logFile << jlogs;
rt300@0 459 cout << jlogs;
rt300@0 460 logFile.close();
rt300@0 461
rt300@0 462 }
rt300@0 463 //---------------------------------------------------------------------------
rt300@0 464
rt300@0 465 Json::Value EventLogger::logsToJson(){
rt300@0 466 // put all logged events into Json formatted string
rt300@0 467 Json::Value root;
rt300@0 468
rt300@0 469 vector<lEvent>::iterator eventIter;
rt300@0 470
rt300@0 471 root["programVersion"] = PROGRAM_VERSION;
rt300@0 472 root["userName"] = userName;
rt300@0 473 root["deviceID"] = deviceID;
rt300@0 474 root["uploadNumber"] = nextUploadNumber;
rt300@0 475 root["savedInteractionTime"] = savedInteractionTime;
rt300@0 476 root["questionnaireCompleted"] = questionnaireCompleted;
rt300@0 477 root["questionnaireUploaded"] = questionnaireUploaded;
rt300@0 478
rt300@0 479 // this can mess up matlab script if it doesn't find this field
rt300@0 480 root["questionnaire"] = questionnaireToJson();
rt300@0 481
rt300@0 482
rt300@0 483 int i = 0;
rt300@0 484 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
rt300@0 485 root["events"][i] = (*eventIter).eventToJson();
rt300@0 486 i++;
rt300@0 487 }
rt300@0 488 root["numEventsHere"] = i;
rt300@0 489 return root;
rt300@0 490 }
rt300@0 491
rt300@0 492 //---------------------------------------------------------------------------
rt300@0 493
rt300@0 494 Json::Value EventLogger::questionnaireToJson(){
rt300@0 495 // put all answers into Json formatted string
rt300@0 496 Json::Value root;
rt300@0 497
rt300@0 498 vector<int>::iterator aIter;
rt300@0 499
rt300@0 500 Json::Value questionnaire;
rt300@0 501
rt300@0 502 int i = 0;
rt300@0 503 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
rt300@0 504 questionnaire[i] = (*aIter);
rt300@0 505 i++;
rt300@0 506 }
rt300@0 507
rt300@0 508 root["qAnswers"] = questionnaire;
rt300@0 509 root["comments"] = questionnaireComments;
rt300@0 510 root["userName"] = userName;
rt300@0 511 root["deviceID"] = deviceID;
rt300@0 512 root["programVersion"] = PROGRAM_VERSION;
rt300@0 513
rt300@0 514 return root;
rt300@0 515 }
rt300@0 516
rt300@0 517 //---------------------------------------------------------------------------
rt300@0 518 void EventLogger::printAll(){
rt300@0 519 cout << "-----------------ALL LOGGED EVENTS----------------- \n";
rt300@0 520 vector<lEvent>::iterator evIter;
rt300@0 521 cout << logsToJson() << "\n";
rt300@0 522 cout << "---------------------QUESTIONNAIRE---------------- \n";
rt300@0 523 cout << questionnaireToJson() << "\n";
rt300@0 524 };
rt300@0 525 //---------------------------------------------------------------------------
rt300@0 526
rt300@0 527 void EventLogger::saveSessionToFile(){
rt300@0 528 stringstream fn;
rt300@0 529 fn << ofxiPhoneGetDocumentsDirectory() << userName << '_' << sessionStartTime << "_BACKUP.json";
rt300@0 530
rt300@0 531 string fname = fn.str(); //ofxiPhoneGetDocumentsDirectory() + userName + '_' + "TESTSAVE.json";
rt300@0 532
rt300@0 533 // write to file
rt300@0 534 // json without the logs that were uploaded!
rt300@0 535 Json::Value jlogs = logsToJson();
rt300@0 536 ofFile logFile(fname,ofFile::WriteOnly);
rt300@0 537 logFile << jlogs;
rt300@0 538 logFile.close();
rt300@0 539
rt300@0 540 }
rt300@0 541 //----------------------------------------------------------------------------
rt300@0 542
rt300@0 543 // this builds up a file incrementally, which can be recovered on crash
rt300@0 544 //void EventLogger::appendToFile(){
rt300@0 545 //
rt300@0 546 //
rt300@0 547 //}