the most flexible way is to listen to events via an ESL socket, and react on important events by generating CDR, or updating your database, etc.
Here's an example in Perl:
https://wiki.freeswitch.org/wiki/CDR_via_ESL It generates a new CDR upon hangup. If you need to process the start of the outbound call, your event will probably be CHANNEL_BRIDGE.
For a server with some intensive load, it's better to utilize multithreading and queing, so that the ESL listening thread is not delayed by CDR writing. This could be done in a number of programming languages (my favorite would be Go).