Kaynağa Gözat

Experimental interface to get statistics data on connections

This interface may be changed or completely removed later.
It provices additional statistics data (See #243).
This is step 1 for test purposes - more data will follow if it works.
bel2125 8 yıl önce
ebeveyn
işleme
150481ba40
4 değiştirilmiş dosya ile 187 ekleme ve 7 silme
  1. 26 0
      include/civetweb.h
  2. 115 0
      src/civetweb.c
  3. 42 6
      src/mod_lua.inl
  4. 4 1
      test/page_status.lua

+ 26 - 0
include/civetweb.h

@@ -1243,6 +1243,32 @@ CIVETWEB_API int mg_get_system_info(char *buffer, int buflen);
 CIVETWEB_API int
 mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen);
 
+
+#define MG_EXPERIMENTAL_INTERFACES
+
+#ifdef MG_EXPERIMENTAL_INTERFACES
+/* Get connection information. Useful for server diagnosis.
+   Parameters:
+     ctx: Context handle
+     idx: Connection index
+     buffer: Store context information here.
+     buflen: Length of buffer (including a byte required for a terminating 0).
+   Return:
+     Available size of system information, exluding a terminating 0.
+     The information is complete, if the return value is smaller than buflen.
+   Note:
+     It is possible to determine the required buflen, by first calling this
+     function with buffer = NULL and buflen = NULL. The required buflen is
+     one byte more than the returned value. However, since the available
+     context information changes, you should allocate a few bytes more.
+*/
+CIVETWEB_API int mg_get_connection_info(const struct mg_context *ctx,
+                                        int idx,
+                                        char *buffer,
+                                        int buflen);
+#endif
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

+ 115 - 0
src/civetweb.c

@@ -17004,6 +17004,103 @@ mg_get_context_info_impl(const struct mg_context *ctx, char *buffer, int buflen)
 #endif
 
 
+#ifdef MG_EXPERIMENTAL_INTERFACES
+/* Get connection information. It can be printed or stored by the caller.
+ * Return the size of available information. */
+static int
+mg_get_connection_info_impl(const struct mg_context *ctx,
+                            int idx,
+                            char *buffer,
+                            int buflen)
+{
+	const struct mg_connection *conn;
+	char block[256];
+	int connection_info_length = 0;
+
+#if defined(_WIN32)
+	const char *eol = "\r\n";
+#else
+	const char *eol = "\n";
+#endif
+
+	const char *eoobj = "}";
+	int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
+
+	if ((buffer == NULL) || (buflen < 10)) {
+		buflen = 0;
+	}
+
+	if ((ctx == NULL) || (idx < 0)) {
+		/* Parameter error */
+		return 0;
+	}
+
+	if ((unsigned)idx >= ctx->cfg_worker_threads) {
+		/* Out of range */
+		return 0;
+	}
+
+	/* Take connection [idx]. This connection is not locked in
+	 * any way, so some other thread might use it. */
+	conn = (ctx->worker_connections) + idx;
+
+	/* Initialize output string */
+	mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
+	connection_info_length += (int)strlen(block);
+	if (connection_info_length < buflen) {
+		strcat(buffer, block);
+	}
+
+	/* Execution time information */
+	if (ctx) {
+		char start_time_str[64] = {0};
+		char now_str[64] = {0};
+		time_t start_time = conn->conn_birth_time;
+		time_t now = time(NULL);
+
+		gmt_time_string(start_time_str,
+		                sizeof(start_time_str) - 1,
+		                &start_time);
+		gmt_time_string(now_str, sizeof(now_str) - 1, &now);
+
+		mg_snprintf(NULL,
+		            NULL,
+		            block,
+		            sizeof(block),
+		            "\"time\" : {%s"
+		            "\"uptime\" : %.0f,%s"
+		            "\"start\" : \"%s\",%s"
+		            "\"now\" : \"%s\"%s"
+		            "}%s",
+		            eol,
+		            difftime(now, start_time),
+		            eol,
+		            start_time_str,
+		            eol,
+		            now_str,
+		            eol,
+		            eol);
+
+		connection_info_length += (int)strlen(block);
+		if (connection_info_length + reserved_len < buflen) {
+			strcat(buffer, block);
+		}
+	}
+
+	/* Terminate string */
+	if ((buflen > 0) && buffer && buffer[0]) {
+		if (connection_info_length < buflen) {
+			strcat(buffer, eoobj);
+			strcat(buffer, eol);
+			connection_info_length += reserved_len;
+		}
+	}
+
+	return connection_info_length;
+}
+#endif
+
+
 /* Get system information. It can be printed or stored by the caller.
  * Return the size of available information. */
 int
@@ -17042,6 +17139,24 @@ mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
 }
 
 
+#ifdef MG_EXPERIMENTAL_INTERFACES
+int
+mg_get_connection_info(const struct mg_context *ctx,
+                       int idx,
+                       char *buffer,
+                       int buflen)
+{
+	if ((buffer == NULL) || (buflen < 1)) {
+		return mg_get_connection_info_impl(ctx, idx, NULL, 0);
+	} else {
+		/* Reset buffer, so we can always use strcat. */
+		buffer[0] = 0;
+		return mg_get_connection_info_impl(ctx, idx, buffer, buflen);
+	}
+}
+#endif
+
+
 /* Initialize this library. This function does not need to be thread safe.
  */
 unsigned

+ 42 - 6
src/mod_lua.inl

@@ -1021,17 +1021,18 @@ static int
 lsp_get_info(lua_State *L)
 {
 	int num_args = lua_gettop(L);
-	int type1;
-	const char *arg;
+	int type1, type2;
+	const char *arg1;
+	double arg2;
 	int len;
 	char *buf;
 
 	if (num_args == 1) {
 		type1 = lua_type(L, 1);
 		if (type1 == LUA_TSTRING) {
-			arg = lua_tostring(L, 1);
+			arg1 = lua_tostring(L, 1);
 			/* Get info according to argument */
-			if (!mg_strcasecmp(arg, "system")) {
+			if (!mg_strcasecmp(arg1, "system")) {
 				/* Get system info */
 				len = mg_get_system_info(NULL, 0);
 				buf = mg_malloc(len + 64);
@@ -1043,7 +1044,7 @@ lsp_get_info(lua_State *L)
 				mg_free(buf);
 				return 1;
 			}
-			if (!mg_strcasecmp(arg, "context")) {
+			if (!mg_strcasecmp(arg1, "context")) {
 				/* Get context */
 				struct mg_context *ctx;
 				lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
@@ -1061,7 +1062,7 @@ lsp_get_info(lua_State *L)
 				mg_free(buf);
 				return 1;
 			}
-			if (!mg_strcasecmp(arg, "common")) {
+			if (!mg_strcasecmp(arg1, "common")) {
 				/* Get context info for NULL context */
 				len = mg_get_context_info(NULL, NULL, 0);
 				buf = mg_malloc(len + 64);
@@ -1077,6 +1078,41 @@ lsp_get_info(lua_State *L)
 		}
 	}
 
+#ifdef MG_EXPERIMENTAL_INTERFACES
+	if (num_args == 2) {
+		type1 = lua_type(L, 1);
+		type2 = lua_type(L, 2);
+		if ((type1 == LUA_TSTRING) && (type2 == LUA_TNUMBER)) {
+			arg1 = lua_tostring(L, 1);
+			arg2 = lua_tonumber(L, 2);
+
+			/* Get info according to argument */
+			if (!mg_strcasecmp(arg1, "connection")) {
+
+				/* Get context */
+				struct mg_context *ctx;
+				lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+				lua_gettable(L, LUA_REGISTRYINDEX);
+				ctx = (struct mg_context *)lua_touserdata(L, -1);
+
+				/* Get connection info for connection idx */
+				int idx = (int)(arg2 + 0.5);
+
+				len = mg_get_connection_info(ctx, idx, NULL, 0);
+				buf = mg_malloc(len + 64);
+				if (!buf) {
+					return luaL_error(L, "OOM in get_info() call");
+				}
+				len = mg_get_connection_info(ctx, idx, buf, len + 63);
+				lua_pushlstring(L, buf, len);
+				mg_free(buf);
+				return 1;
+			}
+			return 0;
+		}
+	}
+#endif
+
 	/* Syntax error */
 	return luaL_error(L, "invalid get_info() call");
 }

+ 4 - 1
test/page_status.lua

@@ -7,5 +7,8 @@ mg.write("</p>\r\n<p>\r\n")
 mg.write(mg.get_info("context"))
 mg.write("</p>\r\n<p>\r\n")
 mg.write(mg.get_info("common"))
+for i=1,100 do
+  mg.write("</p>\r\n<p>\r\n")
+  mg.write(mg.get_info("connection", i))
+end
 mg.write("</p></body></html>\r\n")
-