Is printf in timer callback a good idea?

As AndyA explains, it is not a good idea. You want to get out of an ISR context as soon as possible.

I generally use EventQueue to defer an execution of code. Here is an example.

#include "mbed.h" 

Ticker ticker;
EventQueue *queue = mbed_event_queue(); // event queue
int counter = 0;

void processInUserContext() {
    printf("printing in a user context. counter = %d\r\n", counter);
}

void tickerCallback() {
    counter += 1;
    queue->call(&processInUserContext); // defer the execution to a different context
} 
 
int main() {
    ticker.attach(&tickerCallback, 1.0);       
    queue->dispatch_forever();
}

This page explains the power of EventQueue.

My answers to another topic may be helpful too.