@@ -285,7 +285,78 @@ static int mcplib_backend_wrap_gc(lua_State *L) {
285
285
}
286
286
287
287
static int mcplib_backend_gc (lua_State * L ) {
288
- return 0 ; // no-op.
288
+ mcp_backend_label_t * be = lua_touserdata (L , 1 );
289
+ if (be -> logging .detail_hit )
290
+ free (be -> logging .detail_hit );
291
+ if (be -> logging .detail_ok )
292
+ free (be -> logging .detail_ok );
293
+ if (be -> logging .detail_err )
294
+ free (be -> logging .detail_err );
295
+
296
+ return 0 ;
297
+ }
298
+
299
+ static int _mcplib_backend_log (lua_State * L , mcp_backend_label_t * be ) {
300
+ be -> use_logging = true;
301
+
302
+ if (lua_getfield (L , -1 , "deadline" ) != LUA_TNIL ) {
303
+ int deadline = luaL_checkinteger (L , -1 );
304
+ if (deadline < 0 ) {
305
+ proxy_lua_error (L , "backend log deadline must be >= 0" );
306
+ }
307
+ // convert to milliseconds.
308
+ be -> logging .deadline = deadline * 1000 ;
309
+ }
310
+ lua_pop (L , 1 );
311
+
312
+ if (lua_getfield (L , -1 , "rate" ) != LUA_TNIL ) {
313
+ int rate = luaL_checkinteger (L , -1 );
314
+ if (rate < 0 ) {
315
+ proxy_lua_error (L , "backend log sample rate must be >= 0" );
316
+ }
317
+ be -> logging .rate = rate ;
318
+ }
319
+ lua_pop (L , 1 );
320
+
321
+ if (lua_getfield (L , -1 , "errors" ) != LUA_TNIL ) {
322
+ luaL_checktype (L , -1 , LUA_TBOOLEAN );
323
+ int errors = lua_toboolean (L , -1 );
324
+ if (errors ) {
325
+ be -> logging .all_errors = true;
326
+ } else {
327
+ be -> logging .all_errors = false;
328
+ }
329
+ }
330
+ lua_pop (L , 1 );
331
+
332
+ if (lua_getfield (L , -1 , "tag_hit" ) != LUA_TNIL ) {
333
+ size_t tlen = 0 ;
334
+ const char * tag = luaL_checklstring (L , -1 , & tlen );
335
+ be -> logging .detail_hit = malloc (tlen + 1 );
336
+ memcpy (be -> logging .detail_hit , tag , tlen );
337
+ be -> logging .detail_hit [tlen ] = '\0' ;
338
+ }
339
+ lua_pop (L , 1 );
340
+
341
+ if (lua_getfield (L , -1 , "tag_ok" ) != LUA_TNIL ) {
342
+ size_t tlen = 0 ;
343
+ const char * tag = luaL_checklstring (L , -1 , & tlen );
344
+ be -> logging .detail_ok = malloc (tlen + 1 );
345
+ memcpy (be -> logging .detail_ok , tag , tlen );
346
+ be -> logging .detail_ok [tlen ] = '\0' ;
347
+ }
348
+ lua_pop (L , 1 );
349
+
350
+ if (lua_getfield (L , -1 , "tag_err" ) != LUA_TNIL ) {
351
+ size_t tlen = 0 ;
352
+ const char * tag = luaL_checklstring (L , -1 , & tlen );
353
+ be -> logging .detail_err = malloc (tlen + 1 );
354
+ memcpy (be -> logging .detail_err , tag , tlen );
355
+ be -> logging .detail_err [tlen ] = '\0' ;
356
+ }
357
+ lua_pop (L , 1 );
358
+
359
+ return 0 ;
289
360
}
290
361
291
362
// backend label object; given to pools which then find or create backend
@@ -298,15 +369,18 @@ static int mcplib_backend(lua_State *L) {
298
369
size_t llen = 0 ;
299
370
size_t nlen = 0 ;
300
371
size_t plen = 0 ;
301
- proxy_ctx_t * ctx = PROXY_GET_CTX (L );
302
- mcp_backend_label_t * be = lua_newuserdatauv (L , sizeof (mcp_backend_label_t ), 0 );
303
- memset (be , 0 , sizeof (* be ));
304
372
const char * label ;
305
373
const char * name ;
306
374
const char * port ;
375
+ proxy_ctx_t * ctx = PROXY_GET_CTX (L );
376
+ mcp_backend_label_t * be = lua_newuserdatauv (L , sizeof (mcp_backend_label_t ), 0 );
377
+ memset (be , 0 , sizeof (* be ));
307
378
// copy global defaults for tunables.
308
379
memcpy (& be -> tunables , & ctx -> tunables , sizeof (be -> tunables ));
309
380
be -> conncount = 1 ; // one connection per backend as default.
381
+ // set the metatable early so the GC handler can free partial allocations
382
+ luaL_getmetatable (L , "mcp.backend" );
383
+ lua_setmetatable (L , -2 ); // set metatable to userdata.
310
384
311
385
if (lua_istable (L , 1 )) {
312
386
@@ -455,6 +529,14 @@ static int mcplib_backend(lua_State *L) {
455
529
}
456
530
lua_pop (L , 1 );
457
531
532
+ if (lua_getfield (L , 1 , "log" ) != LUA_TNIL ) {
533
+ if (lua_istable (L , -1 )) {
534
+ _mcplib_backend_log (L , be );
535
+ } else {
536
+ proxy_lua_error (L , "backend log option must be a table" );
537
+ }
538
+ }
539
+ lua_pop (L , 1 );
458
540
} else {
459
541
label = luaL_checklstring (L , 1 , & llen );
460
542
name = luaL_checklstring (L , 2 , & nlen );
@@ -486,8 +568,6 @@ static int mcplib_backend(lua_State *L) {
486
568
if (lua_istable (L , 1 )) {
487
569
lua_pop (L , 3 ); // drop label, name, port.
488
570
}
489
- luaL_getmetatable (L , "mcp.backend" );
490
- lua_setmetatable (L , -2 ); // set metatable to userdata.
491
571
492
572
return 1 ; // return be object.
493
573
}
@@ -530,12 +610,27 @@ static mcp_backend_wrap_t *_mcplib_make_backendconn(lua_State *L, mcp_backend_la
530
610
proxy_lua_error (L , "out of memory allocating backend connection" );
531
611
return NULL ;
532
612
}
613
+
533
614
bew -> be = be ;
534
615
535
616
strncpy (be -> name , bel -> name , MAX_NAMELEN + 1 );
536
617
strncpy (be -> port , bel -> port , MAX_PORTLEN + 1 );
537
618
strncpy (be -> label , bel -> label , MAX_LABELLEN + 1 );
538
619
memcpy (& be -> tunables , & bel -> tunables , sizeof (bel -> tunables ));
620
+ memcpy (& be -> logging , & bel -> logging , sizeof (bel -> logging ));
621
+ be -> use_logging = bel -> use_logging ;
622
+ // TODO: check for errors.
623
+ // not really going to happen and if it does the tag just blanks out..
624
+ if (bel -> logging .detail_hit ) {
625
+ be -> logging .detail_hit = strdup (bel -> logging .detail_hit );
626
+ }
627
+ if (bel -> logging .detail_ok ) {
628
+ be -> logging .detail_ok = strdup (bel -> logging .detail_ok );
629
+ }
630
+ if (bel -> logging .detail_err ) {
631
+ be -> logging .detail_err = strdup (bel -> logging .detail_err );
632
+ }
633
+
539
634
be -> conncount = bel -> conncount ;
540
635
STAILQ_INIT (& be -> iop_head );
541
636
@@ -1397,8 +1492,8 @@ static int mcplib_log_req(lua_State *L) {
1397
1492
rtype = rs -> resp .type ;
1398
1493
rcode = rs -> resp .code ;
1399
1494
rstatus = rs -> status ;
1400
- rname = rs -> be_name ;
1401
- rport = rs -> be_port ;
1495
+ rname = rs -> be -> name ;
1496
+ rport = rs -> be -> port ;
1402
1497
elapsed = rs -> elapsed ;
1403
1498
}
1404
1499
size_t dlen = 0 ;
@@ -1432,6 +1527,57 @@ static uint32_t _mcp_nextrand(uint32_t *s) {
1432
1527
return result ;
1433
1528
}
1434
1529
1530
+ void mcplib_rqu_log (mcp_request_t * rq , mcp_resp_t * rs , int cfd ) {
1531
+ LIBEVENT_THREAD * t = rs -> thread ;
1532
+ logger * l = t -> l ;
1533
+
1534
+ long elapsed = 0 ;
1535
+
1536
+ int rtype = rs -> resp .type ;
1537
+ int rcode = rs -> resp .code ;
1538
+ int rstatus = rs -> status ;
1539
+ elapsed = rs -> elapsed ;
1540
+
1541
+ bool do_log = false;
1542
+ struct proxy_logging * pl = & rs -> be -> logging ;
1543
+ if (pl -> all_errors && rstatus != MCMC_OK ) {
1544
+ do_log = true;
1545
+ } else if (pl -> deadline > 0 && elapsed > pl -> deadline ) {
1546
+ do_log = true;
1547
+ } else if (pl -> rate > 0 ) {
1548
+ // slightly biased random-to-rate without adding a loop, which is
1549
+ // completely fine for this use case.
1550
+ uint32_t rnd = (uint64_t )_mcp_nextrand (t -> proxy_rng ) * (uint64_t )pl -> rate >> 32 ;
1551
+ if (rnd == 0 ) {
1552
+ do_log = true;
1553
+ }
1554
+ }
1555
+
1556
+ if (do_log ) {
1557
+ char * rname = rs -> be -> name ;
1558
+ char * rport = rs -> be -> port ;
1559
+ size_t dlen = 0 ;
1560
+ const char * detail = NULL ;
1561
+
1562
+ // FIXME: confirm this is what we want.
1563
+ // I think this returns HIT in odd circumstances.
1564
+ // might have to check for a "get class" cmd.
1565
+ if (rstatus == MCMC_OK ) {
1566
+ if (rcode != MCMC_CODE_END ) {
1567
+ detail = rs -> be -> logging .detail_hit ;
1568
+ } else {
1569
+ detail = rs -> be -> logging .detail_ok ;
1570
+ }
1571
+ } else {
1572
+ detail = rs -> be -> logging .detail_err ;
1573
+ }
1574
+ if (detail ) {
1575
+ dlen = strlen (detail );
1576
+ }
1577
+
1578
+ logger_log (l , LOGGER_PROXY_REQ , NULL , rq -> pr .request , rq -> pr .reqlen , elapsed , rtype , rcode , rstatus , cfd , detail , dlen , rname , rport );
1579
+ }
1580
+ }
1435
1581
1436
1582
// (milliseconds, sample_rate, allerrors, request, resp, "detail")
1437
1583
static int mcplib_log_reqsample (lua_State * L ) {
@@ -1459,8 +1605,8 @@ static int mcplib_log_reqsample(lua_State *L) {
1459
1605
rtype = rs -> resp .type ;
1460
1606
rcode = rs -> resp .code ;
1461
1607
rstatus = rs -> status ;
1462
- rname = rs -> be_name ;
1463
- rport = rs -> be_port ;
1608
+ rname = rs -> be -> name ;
1609
+ rport = rs -> be -> port ;
1464
1610
elapsed = rs -> elapsed ;
1465
1611
}
1466
1612
size_t dlen = 0 ;
0 commit comments