671f8e4fac56f9dcd5497c1e45e7cda89d98cceb
chmalee
  Wed Apr 19 14:45:03 2023 -0700
Adding an asynchronous logging function for the javascript

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index f3f295a..2c19627 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -21,30 +21,31 @@
 #include "trashDir.h"
 #ifndef GBROWSE
 #include "customFactory.h"
 #include "googleAnalytics.h"
 #include "wikiLink.h"
 #endif /* GBROWSE */
 #include "hgMaf.h"
 #include "hui.h"
 #include "geoMirror.h"
 #include "hubConnect.h"
 #include "trackHub.h"
 #include "cgiApoptosis.h"
 #include "customComposite.h"
 #include "regexHelper.h"
 #include "windowsToAscii.h"
+#include "jsonWrite.h"
 
 static char *sessionVar = "hgsid";	/* Name of cgi variable session is stored in. */
 static char *positionCgiName = "position";
 
 DbConnector cartDefaultConnector = hConnectCart;
 DbDisconnect cartDefaultDisconnector = hDisconnectCart;
 static boolean cartDidContentType = FALSE;
 
 struct slPair *httpHeaders = NULL; // A list of headers to output before the content-type
 
 static void hashUpdateDynamicVal(struct hash *hash, char *name, void *val)
 /* Val is a dynamically allocated (freeMem-able) entity to put
  * in hash.  Override existing hash item with that name if any.
  * Otherwise make new hash item. */
 {
@@ -2340,30 +2341,43 @@
     char *redirect = cgiOptionalString("redirect");
     if (redirect)
         {
         printf("Set-Cookie: redirect=%s; path=/; domain=%s; expires=%s\r\n", redirect, cgiServerName(), cookieDate());
         }
     }
 /* Validate login cookies if login is enabled */
 if (loginSystemEnabled())
     {
     struct slName *newCookies = loginValidateCookies(cart), *sl;
     for (sl = newCookies;  sl != NULL;  sl = sl->next)
         printf("Set-Cookie: %s\r\n", sl->name);
     }
 }
 
+static void cartJsonStart()
+/* Write the necessary headers for Apache */
+{
+puts("Content-Type: application/json\n");
+}
+
+static void cartJsonEnd(struct jsonWrite *jw)
+/* Write the final string which may have nothing in it */
+{
+if (jw)
+    puts(jw->dy->string);
+}
+
 struct cart *cartForSession(char *cookieName, char **exclude,
                             struct hash *oldVars)
 /* This gets the cart without writing any HTTP lines at all to stdout. */
 {
 /* Most cgis call this routine */
 if (sameOk(cfgOption("signalsHandler"), "on"))  /* most cgis call this routine */
     initSigHandlers(hDumpStackEnabled());
 
 /* HTTPS SSL Cert Checking Settings */
 char *httpsCertCheck = cfgOption("httpsCertCheck");  
 if (httpsCertCheck)
     setenv("https_cert_check", httpsCertCheck, TRUE);
 char *httpsCertCheckVerbose = cfgOption("httpsCertCheckVerbose");  
 if (httpsCertCheckVerbose)
     setenv("https_cert_check_verbose", httpsCertCheckVerbose, TRUE);
@@ -2394,30 +2408,41 @@
     setenv("log_proxy", logProxy, TRUE);
 
 /* noSqlInj settings so they are accessible in src/lib too */
 char *noSqlInj_level = cfgOption("noSqlInj.level");
 if (noSqlInj_level)
     setenv("noSqlInj_level", noSqlInj_level, TRUE);
 char *noSqlInj_dumpStack = cfgOption("noSqlInj.dumpStack");
 if (noSqlInj_dumpStack)
     setenv("noSqlInj_dumpStack", noSqlInj_dumpStack, TRUE);
 
 
 // if ignoreCookie is on the URL, don't check for cookies
 char *hguid = NULL;
 if ( cgiOptionalString("ignoreCookie") == NULL )
     hguid = getCookieId(cookieName);
+
+// if _dumpToLog is on the URL, we can exit early with whatever
+// message we are trying to write to the stderr/error_log
+char *logMsg = NULL;
+if ( (logMsg = cgiOptionalString("_dumpToLog")) != NULL)
+    {
+    cartJsonStart();
+    fprintf(stderr, "%s", cgiEncode(logMsg));
+    cartJsonEnd(NULL);
+    exit(0);
+    }
 char *hgsid = getSessionId();
 struct cart *cart = cartNew(hguid, hgsid, exclude, oldVars);
 cartExclude(cart, sessionVar);
 
 // activate optional debuging output for CGIs
 verboseCgi(cartCgiUsualString(cart, "verbose", NULL));
 
 return cart;
 }
 
 static void addHttpHeaders()
 /* CGIs can initialize the global variable httpHeaders to control their own HTTP
  * headers. This allows, for example, to prevent web browser caching of hgTracks
  * responses, but implicitly allow web browser caching everywhere else */
 {