diff --git a/changelog b/changelog
index 9a804c166dc4abdbd0c832b4e287d043c61fb639..4da56ba82cd3a99268fcd18962be43ed463bbc4e 100644
--- a/changelog
+++ b/changelog
@@ -101,6 +101,15 @@ $ wget http://localhost:7681/cgitest --post-file=hello.txt -O- --quiet
 lwstest script
 read="hello"
 
+4) There is a helper api for forming logging timestamps
+
+LWS_VISIBLE int
+lwsl_timestamp(int level, char *p, int len)
+
+this generates this kind of timestamp for use as logging preamble
+
+lwsts[13116]: [2016/01/25 14:52:52:8386] NOTICE: Initial logging level 7
+
 
 
 v1.7.0
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index e10250f7898833ba121bf9f90685286436d43e68..43a0527d8140e4daab1e47c5ad80b42c9f35b3f8 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -952,12 +952,21 @@ lws_ensure_user_space(struct lws *wsi)
 	return 0;
 }
 
-LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
+/**
+ * lwsl_timestamp: generate logging timestamp string
+ *
+ * @level:	logging level
+ * @p:		char * buffer to take timestamp
+ * @len:	length of p
+ *
+ * returns length written in p
+ */
+LWS_VISIBLE int
+lwsl_timestamp(int level, char *p, int len)
 {
 	time_t o_now = time(NULL);
 	unsigned long long now;
 	struct tm *ptm = NULL;
-	char buf[300];
 #ifndef WIN32
 	struct tm tm;
 #endif
@@ -969,13 +978,14 @@ LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
 	if (localtime_r(&o_now, &tm))
 		ptm = &tm;
 #endif
-	buf[0] = '\0';
+	p[0] = '\0';
 	for (n = 0; n < LLL_COUNT; n++) {
 		if (level != (1 << n))
 			continue;
 		now = time_in_microseconds() / 100;
 		if (ptm)
-			sprintf(buf, "[%04d/%02d/%02d %02d:%02d:%02d:%04d] %s: ",
+			n = snprintf(p, len,
+				"[%04d/%02d/%02d %02d:%02d:%02d:%04d] %s: ",
 				ptm->tm_year + 1900,
 				ptm->tm_mon,
 				ptm->tm_mday,
@@ -984,12 +994,21 @@ LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
 				ptm->tm_sec,
 				(int)(now % 10000), log_level_names[n]);
 		else
-			sprintf(buf, "[%llu:%04d] %s: ",
+			n = snprintf(p, len, "[%llu:%04d] %s: ",
 					(unsigned long long) now / 10000,
 					(int)(now % 10000), log_level_names[n]);
-		break;
+		return n;
 	}
 
+	return 0;
+}
+
+LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
+{
+	char buf[50];
+
+	lwsl_timestamp(level, buf, sizeof(buf));
+
 	fprintf(stderr, "%s%s", buf, line);
 }
 
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 5055c2f4d78bd79fd39db75590cfe1802abd0149..fe928026be0f034c637d939d218fb330c303c5eb 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -218,6 +218,8 @@ enum lws_log_levels {
 
 LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...);
 LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl);
+LWS_VISIBLE LWS_EXTERN int
+lwsl_timestamp(int level, char *p, int len);
 
 /* notice, warn and log are always compiled in */
 #define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__)