SD Card logging with card replacements

So yes, I have searched and read many threads about this; and I have been through the SdFat source files and documentation many times... here is why I am still posting this:

  • I couldn't find a simple, clear example of how to log data while supporting card removes/inserts. Lots of instructions of how to do it, but no real sample code
  • I was looking for a solution using SdFat only (I am seriously memory constrained)
  • Many threads are old, and I see several posts from Bill Greinman mentioning updates to improve things and I wasn't sure what applied and what didn't anymore

... so I'd like your thoughts about the code below, and whether it could be improved? The goal is to keep the program running (no resets) while the card is occasionally removed & re-inserted. I do understand that corruption could happen if the card is removed while logging, I'll handle that separately.

I have tested removing / re-inserting the card; and starting w/o a card and inserting it later.

A question I still have: I suspect the **Halt methods may be useful but I am not sure what they do exactly? If I call them every time I detect a failure will the next SD.begin still work?

#include <RTClib.h>
#include <SPI.h>
#include <SdFat.h>

#define SS_PIN 10
#define print2(F,V) if (V < 10) F.print('0'); F.print(V, DEC)

// clock
RTC_DS1307 rtc;

// SD Card
SdFat SD;

uint16_t log_id;
bool sdSetup(bool force = false);

void setup()
{
  Serial.begin(9600);
  rtcSetup();
  sdSetup(true);
}

void rtcSetup()
{
  while (! rtc.begin()) {
    Serial.println("RTC not found!");
    delay(1000);
  }
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running, setting the time");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  else {
    Serial.println("RTC is running");
  }
}

bool sdSetup(bool force)
{
  if (force || SD.cardErrorCode()) {
    Serial.println("\nInitializing SD card...");
    SD.begin(SS_PIN);

    if (SD.cardErrorCode()) {
      Serial.print("SD Card init failed! "); SD.errorPrint(&Serial);
    }
  }
  return ! SD.cardErrorCode();
}

void loop () {
  writeLog();
  delay(10000);
}

void writeLog()
{
  SdFile log;
  if (! sdSetup()) {
    return;
  }

  if (! log.open(SD.vwd(), "test.csv", FILE_WRITE)) {
    Serial.print("Could not open file: "); SD.errorPrint(&Serial);
    return;
  }

  DateTime now = rtc.now();

  log.print(log_id); log.print(' ');
  log.print(now.year(), DEC);
  log.print('-'); print2(log, now.month());
  log.print('-'); print2(log, now.day());
  log.print(' '); print2(log, now.hour());
  log.print(':'); print2(log, now.minute());
  log.print(':'); print2(log, now.second());
  log.println();

  bool log_ok = log.close() && ! log.getError();
  if (log_ok) {
    Serial.println("Log written");
    log_id++;
  }
  else {
    Serial.print("Could not write log: "); SD.errorPrint(&Serial);
  }
}