diff --git a/quad/src/quad_app/log_data.c b/quad/src/quad_app/log_data.c
index a72129f13aa22942f1884e3c3608f7227c21405e..d7a361dfe69963339efd502e89cf697446bfe5eb 100644
--- a/quad/src/quad_app/log_data.c
+++ b/quad/src/quad_app/log_data.c
@@ -8,6 +8,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 #include "PID.h"
 #include "type_def.h"
 #include "log_data.h"
@@ -16,7 +17,7 @@
 #include "node_pid.h"
 #include "node_constant.h"
 #include "node_mixer.h"
- 
+
 // Current index of the log array
 int arrayIndex = 0;
 // Size of the array
@@ -27,12 +28,20 @@ struct graph_tuple { // Tuple for
     int sub_id;
 };
 
+// Holds a statically allocated string, as well as info about its size and capacity
+// Used by safe_sprintf_cat
 struct str {
 	char* str;
 	size_t size;
 	size_t capacity;
 };
 
+
+ /**
+  * Forward declarations
+  */
+ void format_log(int idx, log_t* log_struct, struct str* buf);
+
 struct graph_tuple log_outputs[MAX_LOG_NUM];
 struct graph_tuple log_params[MAX_LOG_NUM];
 size_t n_outputs;
@@ -46,32 +55,40 @@ static char units_param_str[512] = {};
 static struct str units_output = { .str = units_output_str, .size = 0, .capacity = sizeof(units_output_str)};
 static struct str units_param = { .str = units_param_str, .size = 0, .capacity = sizeof(units_output_str)};
 
-void safe_strcat(struct str *str, const char* to_add) {
-	size_t add_len = strlen(to_add);
-	if (add_len + str->size <= str->capacity) {
-		strcpy(&(str->str[str->size]), to_add);
-		str->size += add_len;
+/*
+ * Does an sprintf and concatenation. Used just like sprintf, but pass in a pointer to a struct str instead.
+ * Returns the number of bytes that would have been written (just like snprintf)
+ * Will not write more than is available in the given string
+*/
+int safe_sprintf_cat(struct str *str, const char *fmt, ...) {
+	size_t available = str->capacity - str->size;
+	va_list args;
+	va_start(args, fmt);
+	// Print to offset not more than remaining capacity characters
+	size_t full_size = vsnprintf(str->str + str->size, available, fmt, args);
+	va_end(args);
+	if (full_size >= available) { // Check for truncation
+		str->size = str->capacity;
+	} else {
+		str->size = str->size + full_size;
 	}
+	return full_size;
 }
 
 void addOutputToLog(log_t* log_struct, int controller_id, int output_id, char* units) {
-	static char units_buf[64];
 	if (n_outputs < MAX_LOG_NUM) {
 		log_outputs[n_outputs].block_id = controller_id;
 		log_outputs[n_outputs].sub_id = output_id;
 		n_outputs++;
-		snprintf(units_buf, sizeof(units_buf), "\t%s", units);
-		safe_strcat(&units_output, units_buf);
+		safe_sprintf_cat(&units_output, "\t%s", units);
 	}
 }
 void addParamToLog(log_t* log_struct, int controller_id, int param_id, char* units) {
-	static char units_buf[64];
 	if (n_params < MAX_LOG_NUM) {
 		log_params[n_params].block_id = controller_id;
 		log_params[n_params].sub_id = param_id;
 		n_params++;
-		snprintf(units_buf, sizeof(units_buf), "\t%s", units);
-		safe_strcat(&units_param, units_buf);
+		safe_sprintf_cat(&units_param, "\t%s", units);
 	}
 }
 
@@ -158,78 +175,73 @@ void printLogging(hardware_t *hardware_struct, log_t* log_struct, parameter_t* p
 		// Don't send any logs if nothing was logged
 		return;
 	}
-	int i;//, j;
-	// TODO: Change these to struct str so we can use safe_strcat
-	char buf[2560] = {};
-	buf[0] = 0; // Mark buffer as size 0
-	char comments[256] = {};
-	char header1[256] = {};
-	char header2[1024] = {};
+	char buf_arr[2560] = {};
+	struct str buf = {.str = buf_arr, .size = 0, .capacity = sizeof(buf_arr)};
 
 	// Let user know that allocation failed
 	if (arraySize != LOG_STARTING_SIZE) {
-		size_t send_len = sprintf(header1, "Failed to allocate enough log memory\n");
-		send_data(&hardware_struct->uart, LOG_ID, 0, header1, send_len);
+		safe_sprintf_cat(&buf, "Failed to allocate enough log memory\n");
+		send_data(&hardware_struct->uart, LOG_ID, 0, buf.str, buf.size);
 		return;
 	}
+	// Comment header
+	safe_sprintf_cat(&buf, "# MicroCART On-board Quad Log\n# Sample size: %d\n", arrayIndex);
+	// Header names for the pre-defined values
+	safe_sprintf_cat(&buf, "time\taccel_x\taccel_y\taccel_z\tgyro_x\tgyro_y\tgyro_z");
 
-	sprintf(comments, "# MicroCART On-board Quad Log\n# Sample size: %d\n", arrayIndex);
-	sprintf(header1, "time\taccel_x\taccel_y\taccel_z\tgyro_x\tgyro_y\tgyro_z");
-
-	int end = 0;
+	int i;
 	// Print all the recorded block parameters
 	for (i = 0; i < n_params; i++) {
 		const char* block_name = ps->graph->nodes[log_params[i].block_id].name;
 		const char* output_name = ps->graph->nodes[log_params[i].block_id].type->param_names[log_params[i].sub_id];
-		end += sprintf(&header2[end], "\t%s_%s", block_name, output_name);
+		safe_sprintf_cat(&buf, "\t%s_%s", block_name, output_name);
 	}
 	// Print all the recorded block outputs
 	for (i = 0; i < n_outputs; i++) {
 		const char* block_name = ps->graph->nodes[log_outputs[i].block_id].name;
 		const char* param_name = ps->graph->nodes[log_outputs[i].block_id].type->output_names[log_outputs[i].sub_id];
-		end += sprintf(&header2[end], "\t%s_%s", block_name, param_name);
+		safe_sprintf_cat(&buf, "\t%s_%s", block_name, param_name);
 	}
-	end += sprintf(&header2[end], "\n");
+	safe_sprintf_cat(&buf, "\n");
 
 	// Send header names
-	strcat(buf, comments);
-	strcat(buf, header1);
-	strcat(buf, header2);
-	send_data(&hardware_struct->uart, LOG_ID, 0, buf, strlen(buf));
+	send_data(&hardware_struct->uart, LOG_ID, 0, buf.str, buf.size);
 
 	// Send units header
-	buf[0] = 0;
-	strcat(buf, "s\tG\tG\tG\trad/s\trad/s\trad/s"); // The pre-defined ones
-	strcat(buf, units_output.str);
-	strcat(buf, units_param.str);
-	strcat(buf, "\n");
-	send_data(&hardware_struct->uart, LOG_ID, 0, buf, strlen(buf));
+	buf.size = 0;
+	safe_sprintf_cat(&buf, "s\tG\tG\tG\trad/s\trad/s\trad/s"); // The pre-defined ones
+	safe_sprintf_cat(&buf, units_output.str);
+	safe_sprintf_cat(&buf, units_param.str);
+	safe_sprintf_cat(&buf, "\n");
+	send_data(&hardware_struct->uart, LOG_ID, 0, buf.str, buf.size);
 
 	/*************************/
 	/* print & send log data */
 	for(i = 0; i < arrayIndex; i++){
-		int size = format_log(i, log_struct, buf);
-		send_data(&hardware_struct->uart, LOG_ID, 0, buf, size);
+		format_log(i, log_struct, &buf);
+		send_data(&hardware_struct->uart, LOG_ID, 0, buf.str, buf.size);
 	}
 
-	char data[1] = {0}; // 1 byte to make compilers happy
-	send_data(&hardware_struct->uart, LOG_END_ID, 0, data, 0);
+	// Empty message of type LOG_END to indicate end of log
+	send_data(&hardware_struct->uart, LOG_END_ID, 0, buf.str, 0);
 }
 
 void resetLogging() {
 	arrayIndex = 0;
 }
 
-int format_log(int idx, log_t* log_struct, char* buf) {
+/*
+  * Fills the given buffer as ASCII for the recorded index, and returns the length of the string created
+*/
+void format_log(int idx, log_t* log_struct, struct str* buf) {
 	int i;
-	int end = 0;
-
+	buf->size = 0;
+	
 	float* row = &logArray[idx * row_size  * sizeof(float)];\
 
-	end += sprintf(&buf[end], "%f", row[0]);
+	safe_sprintf_cat(buf, "%f", row[0]);
 	for (i = 1; i < row_size; i++) {
-		end += sprintf(&buf[end], "\t%f", row[i]);
+		safe_sprintf_cat(buf, "\t%f", row[i]);
 	}
-	end += sprintf(&buf[end], "\n");
-	return end;
+	safe_sprintf_cat(buf, "\n");
 }
diff --git a/quad/src/quad_app/log_data.h b/quad/src/quad_app/log_data.h
index 1dd2d1741de4e08be70910221fe67baee995eced..34f1658d02f316918547bc0eedd760bcbf121264 100644
--- a/quad/src/quad_app/log_data.h
+++ b/quad/src/quad_app/log_data.h
@@ -54,9 +54,5 @@ void addParamToLog(log_t* log_struct, int controller_id, int param_id, char* uni
   */
  void resetLogging();
 
- /**
-  * Fills the given buffer as ASCII for the recorded index, and returns the length of the string created
-  */
- int format_log(int idx, log_t* log_struct, char* buf);
 
 #endif /* LOG_DATA_H_ */