annotate eventLogger.mm @ 25:f42a00e3f22d

Logs condensed slightly. Questionnaire button enable. double precision location!!!
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Fri, 01 Feb 2013 17:39:19 +0000
parents a4908ad8c78e
children ae4d2c3ce5e0
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@4 8
rt300@8 9 //---------------------------------------------------------------------------
rt300@0 10 #include "eventLogger.h"
rt300@1 11
rt300@1 12 EventLogger eventLogger;
rt300@1 13
rt300@8 14 //---------------------------------------------------------------------------
rt300@1 15 EventLogger::EventLogger(){
rt300@14 16 //QuestionnaireViewController * questionnaireViewController;
rt300@8 17
rt300@25 18 consentGiven = true; // unless told otherwise by introView
rt300@8 19 loggingEnabled = true;
rt300@22 20 serverConnectionOK = false;
rt300@22 21 questionnaireCompleted = false;
rt300@22 22 questionnaireUploaded = false;
rt300@22 23
rt300@22 24
rt300@22 25 ofxiPhoneDeviceType iOSdeviceType = ofxiPhoneGetDeviceType();
rt300@22 26 cout << "Device: " << iOSdeviceType << '\n';
rt300@22 27
rt300@25 28 nextUploadQty = UPLOAD_CHUNK_SIZE; // amount of data uploaded is always more than UPLOAD_CHUNK_SIZE events
rt300@8 29 }
rt300@8 30 //---------------------------------------------------------------------------
rt300@24 31 // draw() - show path of last N scroll events - can be scrubbed along?
rt300@24 32 //
rt300@24 33 //---------------------------------------------------------------------------
rt300@8 34 void EventLogger::init(){
rt300@4 35
rt300@8 36 readJsonToLog(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME);
rt300@8 37 sessionStartTime = ofGetSystemTime();
rt300@9 38
rt300@9 39 testConnection();
rt300@7 40
rt300@25 41 logEvent(APP_STARTED);
rt300@8 42 }
rt300@8 43 //---------------------------------------------------------------------------
rt300@22 44 void EventLogger::questionnaireAnswersObtained(vector<int> answers){
rt300@22 45
rt300@22 46 questionnaireCompleted = true;
rt300@22 47 questionnaireAnswers = answers;
rt300@22 48
rt300@22 49 uploadQuestionnaire();
rt300@22 50
rt300@22 51 }
rt300@22 52 //---------------------------------------------------------------------------
rt300@22 53 bool EventLogger::uploadQuestionnaire(){
rt300@22 54 // show indicator
rt300@22 55 cout << "^^^^^^^^ UPLOADING QUESTIONNAIRE ^^^^^^^^ \n";
rt300@22 56
rt300@22 57 questionnaireUploaded = sendToServer("questionnaire", questionnaireToJson());
rt300@22 58 return questionnaireUploaded;
rt300@22 59 }
rt300@22 60 //---------------------------------------------------------------------------
rt300@22 61 bool EventLogger::sendToServer(string functionName, Json::Value jsonData){
rt300@22 62 bool sent;
rt300@22 63 string request;
rt300@22 64
rt300@22 65 if(functionName == "testConnection"){
rt300@22 66 request = "http://127.0.0.1:8080/testservice/testConnection?jsontext=";
rt300@22 67 }else if(functionName == "questionnaire"){
rt300@22 68 request = "http://127.0.0.1:8080/testservice/questionnaire?jsontext=";
rt300@22 69 }else if(functionName == "eventlog"){
rt300@22 70 request = "http://127.0.0.1:8080/testservice/eventlog?jsontext=";
rt300@22 71 }
rt300@22 72 Json::FastWriter writer;
rt300@22 73 string jsontext = writer.write( jsonData );
rt300@22 74
rt300@22 75 if (!jsontext.empty() && jsontext[jsontext.length()-1] == '\n') {
rt300@22 76 jsontext.erase(jsontext.length()-1);
rt300@22 77 }
rt300@22 78
rt300@22 79 request.append(jsontext);
rt300@22 80
rt300@9 81 ofURLFileLoader fileLoader;
rt300@9 82 ofHttpResponse resp;
rt300@22 83 resp = fileLoader.get(request);
rt300@24 84 //fileLoader.getAsync(request);
rt300@9 85 cout << "HTTP STATUS " << resp.status << "\n";
rt300@9 86 cout << "HTTP ERROR " << resp.error << "\n";
rt300@22 87 cout << "HTTP DATA " << resp.data << "\n"; // ofBuffer
rt300@9 88
rt300@22 89 stringstream response;
rt300@22 90 response << resp.data;
rt300@22 91
rt300@22 92 if (resp.status == 200){
rt300@22 93 if(response.str() == "OK"){
rt300@22 94
rt300@22 95 sent = true;
rt300@22 96 }else{
rt300@22 97 // not ok
rt300@22 98 // problem serverside
rt300@22 99 sent = false;
rt300@22 100 }
rt300@9 101 }else{
rt300@22 102
rt300@22 103 sent = false;
rt300@9 104 // SHOW AN ALERT TO USER?
rt300@9 105 }
rt300@22 106 return sent;
rt300@22 107 }
rt300@22 108 //---------------------------------------------------------------------------
rt300@22 109 bool EventLogger::testConnection(){
rt300@22 110 Json::Value root;
rt300@22 111 root["test"] = "test";
rt300@22 112
rt300@22 113
rt300@22 114 serverConnectionOK = sendToServer("testConnection", root);
rt300@22 115 if (serverConnectionOK){
rt300@22 116 cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n";
rt300@22 117 }else{
rt300@22 118 cout << "server connection ERROR \n";
rt300@22 119 }
rt300@9 120 }
rt300@9 121 //---------------------------------------------------------------------------
rt300@8 122 void EventLogger::readJsonToLog(const string &jsonFile){
rt300@8 123 Json::Value root;
rt300@8 124 Json::Reader reader;
rt300@5 125
rt300@5 126
rt300@8 127 ifstream theFile(jsonFile.c_str());
rt300@8 128 stringstream fileText;
rt300@8 129 string line;
rt300@8 130 if(!theFile){
rt300@8 131
rt300@8 132 firstEverAppOpen();
rt300@8 133
rt300@8 134 return;
rt300@8 135 }else{
rt300@8 136 while(theFile){
rt300@8 137 theFile >> line;
rt300@9 138 // cout << line; // lots!!!!
rt300@8 139 fileText << line;
rt300@8 140 }
rt300@8 141 theFile.close();
rt300@8 142 }
rt300@8 143
rt300@9 144 cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n";
rt300@9 145
rt300@8 146 bool parsingSuccessful = reader.parse( fileText.str(), root );
rt300@8 147
rt300@8 148 if ( !parsingSuccessful )
rt300@8 149 {
rt300@8 150 // report to the user the failure and their locations in the document.
rt300@22 151 std::cout << "Failed to parse event log JSON: \n"
rt300@8 152 << reader.getFormattedErrorMessages();
rt300@8 153 return;
rt300@8 154 }
rt300@8 155
rt300@8 156 // now put user deets into variables
rt300@8 157 userName = root["userName"].asString();
rt300@8 158 deviceID = root["deviceID"].asLargestInt();
rt300@25 159 nextUploadNumber = root["uploadNumber"].asInt();
rt300@25 160 savedInteractionTime = root["savedInteractionTime"].asLargestInt();
rt300@22 161 questionnaireCompleted = root["questionnaireCompleted"].asBool();
rt300@22 162 questionnaireUploaded = root["questionnaireUploaded"].asBool();
rt300@22 163
rt300@22 164
rt300@22 165 if(questionnaireCompleted && !questionnaireUploaded){
rt300@22 166 // then read it in and upload it
rt300@22 167 Json::Value JArray = root["questionnaireAnswers"];
rt300@22 168 if(JArray.size() < 2){
rt300@22 169 cout << "Error - status of questionnaire is wierd\n";
rt300@22 170 }
rt300@22 171 for ( unsigned int i = 0; i < JArray.size(); i++ )
rt300@22 172 {
rt300@22 173 questionnaireAnswers.push_back(JArray[1].asInt());
rt300@22 174 }
rt300@22 175 uploadQuestionnaire();
rt300@22 176 }
rt300@8 177
rt300@8 178 // check for unuploaded evts
rt300@8 179 const Json::Value jlogs = root["events"];
rt300@8 180
rt300@8 181 for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index]));
rt300@9 182 if(theEvents.size() > nextUploadQty){
rt300@8 183 //try to upload
rt300@22 184 uploadEventLog();
rt300@8 185 }
rt300@8 186 // TODO if the total interaction time is greater than a certain amount && no questions answered - questionnaire time!
rt300@25 187 cout << "Total interaction time: " << savedInteractionTime << '\n';
rt300@9 188
rt300@8 189
rt300@9 190 }
rt300@9 191
rt300@9 192
rt300@9 193 //---------------------------------------------------------------------------
rt300@9 194
rt300@22 195 bool EventLogger::uploadEventLog(){
rt300@22 196 // show indicator
rt300@25 197
rt300@25 198 cout << "^^^^^^^^ ATTEMPTING TO UPLOAD " << theEvents.size() << " EVENTS ^^^^^^^^ .\n";
rt300@9 199
rt300@22 200 bool logUploaded = sendToServer("eventlog", logsToJson());
rt300@22 201 if(!logUploaded){
rt300@9 202 // try later
rt300@25 203 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@9 204 }else{
rt300@9 205
rt300@9 206 // if success - clear memory
rt300@9 207 theEvents.clear();
rt300@25 208 cout << "UPLOAD SUCCESS\n";
rt300@25 209 nextUploadNumber++;
rt300@9 210 }
rt300@22 211 return logUploaded;
rt300@8 212
rt300@1 213 }
rt300@8 214 //----------------------------------------------------------------------------
rt300@9 215 //void EventLogger::deleteLogFile(){
rt300@8 216
rt300@8 217 //---------------------------------------------------------------------------
rt300@8 218
rt300@8 219 void EventLogger::firstEverAppOpen(){
rt300@25 220 cout<<"no event log file - first APP open\n";
rt300@25 221 nextUploadNumber = 0;
rt300@8 222 deviceID = ofGetSystemTimeMicros();
rt300@25 223 savedInteractionTime = 0;
rt300@22 224 questionnaireCompleted = false;
rt300@22 225 questionnaireUploaded = false;
rt300@8 226
rt300@24 227 ((testApp *)ofGetAppPtr())->showIntro();
rt300@25 228 consentGiven = false;
rt300@8 229
rt300@8 230 }
rt300@8 231 //---------------------------------------------------------------------------
rt300@8 232 // called from alertView OK in iViewController
rt300@8 233 void EventLogger::setUsername(const char *u){
rt300@8 234 userName = u;
rt300@7 235
rt300@7 236 }
rt300@8 237
rt300@8 238 //---------------------------------------------------------------------------
rt300@8 239 // log zoom event
rt300@5 240 void EventLogger::logEvent(const leventType& evtType,const TwoVector& centre, const double& scale, const int& sliderID, const double& sliderVal){
rt300@3 241 //cout << "log: " << evtType << "\n";
rt300@1 242
rt300@1 243 // scroll has 2 double coords
rt300@1 244 // zoom has 1 double scale
rt300@1 245 // save preset has 2 coords
rt300@1 246 // switch view has view type
rt300@9 247 // slider change has int slider index and 1 float value
rt300@1 248
rt300@4 249 // get time for key index
rt300@4 250
rt300@5 251 // thinFactor
rt300@5 252 if(!loggingEnabled) return;
rt300@4 253 switch ( evtType ) {
rt300@4 254 case SAVE_PRESET:
rt300@5 255 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 256 // Code
rt300@4 257 break;
rt300@4 258 case SAVE_DESET:
rt300@5 259 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 260 break;
rt300@4 261 case SCROLL:
rt300@5 262 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@5 263 break;
rt300@5 264 case SCROLL_STOPPED:
rt300@5 265 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@22 266 cout << "SCROLL STOPPED EVENT\n";
rt300@22 267 break;
rt300@22 268 case SNAPPED_TO_PRESET:
rt300@22 269 theEvents.push_back(lEvent(evtType,centre.x,centre.y,sliderID));
rt300@22 270 cout << "SCROLL STOPPED EVENT\n";
rt300@4 271 break;
rt300@4 272 case ZOOM:
rt300@5 273 theEvents.push_back(lEvent(evtType,scale));
rt300@4 274 break;
rt300@4 275 case CHANGE_SLIDER:
rt300@5 276 theEvents.push_back(lEvent(evtType,sliderVal , 0.0 , sliderID));
rt300@4 277 break;
rt300@25 278 case SWAP_VIEW:
rt300@25 279 theEvents.push_back(lEvent(evtType,0.0 , 0.0 , sliderID)); // slider ID is which view
rt300@25 280 break;
rt300@4 281 default:
rt300@25 282 // default is just an event type with no values
rt300@25 283 theEvents.push_back(lEvent(evtType));
rt300@4 284 break;
rt300@1 285 }
rt300@8 286 if(theEvents.size() > nextUploadQty){
rt300@7 287 //try to upload
rt300@22 288 uploadEventLog();
rt300@7 289 }
rt300@9 290 //sessionTime = (ofGetSystemTime() - sessionStartTime);
rt300@25 291 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@25 292 if(totalInteractionTime > QUESTIONNAIRE_ENABLE_TIME){
rt300@25 293 TopButtonViewController *tbvc = ((testApp *)ofGetAppPtr())->topButtonViewController;
rt300@25 294 [tbvc enableQuestionButton];
rt300@25 295 }
rt300@1 296 }
rt300@8 297
rt300@8 298 //---------------------------------------------------------------------------
rt300@7 299
rt300@7 300 void EventLogger::exitAndSave(){
rt300@25 301
rt300@25 302 if(!consentGiven){
rt300@25 303 logEvent(CONSENT_DENIED);
rt300@25 304 Json::Value jlogs = logsToJson();
rt300@25 305 // try to upload TODO (no - might hang and prevent exit???)
rt300@25 306 uploadEventLog();
rt300@25 307 return;
rt300@25 308 }
rt300@25 309 logEvent(APP_EXITED);
rt300@25 310 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@7 311 // save user details
rt300@8 312 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@8 313
rt300@25 314 // try to upload TODO (no - might hang and prevent exit???)
rt300@22 315 uploadEventLog();
rt300@7 316
rt300@8 317 // write to file
rt300@25 318 // json without the logs that were uploaded!
rt300@25 319 Json::Value jlogs = logsToJson();
rt300@8 320 ofFile logFile(fname,ofFile::WriteOnly);
rt300@8 321 logFile << jlogs;
rt300@8 322
rt300@8 323 }
rt300@8 324 //---------------------------------------------------------------------------
rt300@8 325
rt300@8 326 Json::Value EventLogger::logsToJson(){
rt300@8 327 // put all logged events into Json formatted string
rt300@8 328 Json::Value root;
rt300@8 329
rt300@8 330 vector<lEvent>::iterator eventIter;
rt300@8 331
rt300@22 332 root["programVersion"] = PROGRAM_VERSION;
rt300@8 333 root["userName"] = userName;
rt300@8 334 root["deviceID"] = deviceID;
rt300@25 335 root["uploadNumber"] = nextUploadNumber;
rt300@22 336 root["iOSdeviceType"] = iOSdeviceType;
rt300@25 337 root["savedInteractionTime"] = savedInteractionTime;
rt300@22 338 root["questionnaireCompleted"] = questionnaireCompleted;
rt300@22 339 root["questionnaireUploaded"] = questionnaireUploaded;
rt300@22 340 if(questionnaireCompleted && !questionnaireUploaded){
rt300@22 341 root["qAnswers"] = questionnaireToJson();
rt300@22 342 }
rt300@8 343
rt300@8 344 int i = 0;
rt300@8 345 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
rt300@8 346 root["events"][i] = (*eventIter).eventToJson();
rt300@8 347 i++;
rt300@7 348 }
rt300@25 349 root["numEventsHere"] = i;
rt300@8 350 return root;
rt300@8 351 }
rt300@22 352
rt300@8 353 //---------------------------------------------------------------------------
rt300@22 354
rt300@22 355 Json::Value EventLogger::questionnaireToJson(){
rt300@22 356 // put all answers into Json formatted string
rt300@22 357 Json::Value root;
rt300@22 358
rt300@22 359 vector<int>::iterator aIter;
rt300@22 360
rt300@22 361 Json::Value questionnaire;
rt300@22 362
rt300@22 363 int i = 0;
rt300@22 364 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
rt300@22 365 questionnaire[i] = (*aIter);
rt300@22 366 i++;
rt300@22 367 }
rt300@22 368
rt300@22 369 root["qAnswers"] = questionnaire;
rt300@22 370 root["userName"] = userName;
rt300@22 371 root["deviceID"] = deviceID;
rt300@22 372 root["iOSdeviceType"] = iOSdeviceType;
rt300@22 373 root["programVersion"] = PROGRAM_VERSION;
rt300@22 374
rt300@22 375 return root;
rt300@22 376 }
rt300@8 377 //---------------------------------------------------------------------------
rt300@8 378 //---------------------------------------------------------------------------
rt300@22 379 //---------------------------------------------------------------------------