<commit_before>/*
 * GwtLogHandler.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/gwt/GwtLogHandler.hpp>

#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <core/Log.hpp>
#include <core/SafeConvert.hpp>
#include <core/system/System.hpp>
#include <core/http/Request.hpp>
#include <core/http/Response.hpp>

#include <core/json/JsonRpc.hpp>

#include <core/gwt/GwtSymbolMaps.hpp>

namespace core {
namespace gwt {

namespace {

// symbol maps
SymbolMaps s_symbolMaps;

// client exception
struct ClientException
{
   std::string message;
   std::string strongName;
   std::vector<StackElement> stack;
};

Error parseClientException(const json::Object exJson, ClientException* pEx)
{
   json::Array stackJson;
   Error error = json::readObject(exJson,
                                  "message", &(pEx->message),
                                  "strong_name", &(pEx->strongName),
                                  "stack", &stackJson);
   if (error)
       return error;

   BOOST_FOREACH(const json::Value& elementJson, stackJson)
   {
      if (!json::isType<json::Object>(elementJson))
         return Error(json::errc::ParamTypeMismatch, ERROR_LOCATION);

      StackElement element;
      Error error = json::readObject(elementJson.get_obj(),
                                     "file_name", &element.fileName,
                                     "class_name", &element.className,
                                     "method_name", &element.methodName,
                                     "line_number", &element.lineNumber);
      if (error)
         return error;

      pEx->stack.push_back(element);
   }

   return Success();
}


std::string formatMethod(const std::string& method)
{
   if (!method.empty() && method[0] == '$')
      return method.substr(1);
   else
      return method;
}

bool isExceptionMechanismElement(const StackElement& element)
{
   return boost::algorithm::ends_with(element.methodName, "fillInStackTrace")

          ||

          boost::algorithm::ends_with(element.methodName, "createStackTrace")

          ||

          boost::algorithm::starts_with(element.fileName,
                                   "com/google/gwt/emul/java/lang/Throwable")

          ||

          (boost::algorithm::starts_with(element.fileName,
                                        "com/google/gwt/emul/java/lang/")
          &&

          boost::algorithm::ends_with(element.fileName,
                                      "Exception.java"));
}

void handleLogExceptionRequest(const std::string& username,
                               const std::string& userAgent,
                               const json::JsonRpcRequest& jsonRpcRequest,
                               http::Response* pResponse)
{
   // read client exception json object
   json::Object exJson;
   Error error = json::readParam(jsonRpcRequest.params, 0, &exJson);
   if (error)
   {
      LOG_ERROR(error);
      json::setJsonRpcError(error, pResponse);
      return;
   }
   

   // parse
   ClientException ex;
   error = parseClientException(exJson, &ex);
   if (error)
   {
      LOG_ERROR(error);
      json::setJsonRpcError(error, pResponse);
      return;
   }

   // resymbolize the stack
   std::vector<StackElement> stack = s_symbolMaps.resymbolize(ex.stack,
                                                              ex.strongName);

   // build the log message
   bool printFrame = false;
   std::ostringstream ostr;
   BOOST_FOREACH(const StackElement& element, stack)
   {
      // skip past java/lang/Exception entries
      if (!printFrame)
      {
         if (!isExceptionMechanismElement(element))
            printFrame = true;
      }

      if (printFrame)
      {
         ostr << element.fileName << "#" << element.lineNumber
              << "::" << formatMethod(element.methodName)
              << std::endl;
      }
   }

   // form the log entry
   boost::format fmt("CLIENT EXCEPTION (%1%): %2%%3%\n"
                     "%4%"
                     "Client-ID: %5%\n"
                     "User-Agent: %6%");
   std::string logEntry = boost::str(
                        fmt % log::cleanDelims(username)
                            % log::cleanDelims(ex.message)
                            % log::DELIM
                            % log::cleanDelims(ostr.str())
                            % log::cleanDelims(jsonRpcRequest.clientId)
                            % log::cleanDelims(userAgent));

   // log it
   core::system::log(core::system::kLogLevelError, logEntry);


   // set void result<commit_msg>add ression prefix to logging of client errors<commit_after>/*
 * GwtLogHandler.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/gwt/GwtLogHandler.hpp>

#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <core/Log.hpp>
#include <core/SafeConvert.hpp>
#include <core/system/System.hpp>
#include <core/http/Request.hpp>
#include <core/http/Response.hpp>

#include <core/json/JsonRpc.hpp>

#include <core/gwt/GwtSymbolMaps.hpp>

namespace core {
namespace gwt {

namespace {

// symbol maps
SymbolMaps s_symbolMaps;

// client exception
struct ClientException
{
   std::string message;
   std::string strongName;
   std::vector<StackElement> stack;
};

Error parseClientException(const json::Object exJson, ClientException* pEx)
{
   json::Array stackJson;
   Error error = json::readObject(exJson,
                                  "message", &(pEx->message),
                                  "strong_name", &(pEx->strongName),
                                  "stack", &stackJson);
   if (error)
       return error;

   BOOST_FOREACH(const json::Value& elementJson, stackJson)
   {
      if (!json::isType<json::Object>(elementJson))
         return Error(json::errc::ParamTypeMismatch, ERROR_LOCATION);

      StackElement element;
      Error error = json::readObject(elementJson.get_obj(),
                                     "file_name", &element.fileName,
                                     "class_name", &element.className,
                                     "method_name", &element.methodName,
                                     "line_number", &element.lineNumber);
      if (error)
         return error;

      pEx->stack.push_back(element);
   }

   return Success();
}


std::string formatMethod(const std::string& method)
{
   if (!method.empty() && method[0] == '$')
      return method.substr(1);
   else
      return method;
}

bool isExceptionMechanismElement(const StackElement& element)
{
   return boost::algorithm::ends_with(element.methodName, "fillInStackTrace")

          ||

          boost::algorithm::ends_with(element.methodName, "createStackTrace")

          ||

          boost::algorithm::starts_with(element.fileName,
                                   "com/google/gwt/emul/java/lang/Throwable")

          ||

          (boost::algorithm::starts_with(element.fileName,
                                        "com/google/gwt/emul/java/lang/")
          &&

          boost::algorithm::ends_with(element.fileName,
                                      "Exception.java"));
}

void handleLogExceptionRequest(const std::string& username,
                               const std::string& userAgent,
                               const json::JsonRpcRequest& jsonRpcRequest,
                               http::Response* pResponse)
{
   // read client exception json object
   json::Object exJson;
   Error error = json::readParam(jsonRpcRequest.params, 0, &exJson);
   if (error)
   {
      LOG_ERROR(error);
      json::setJsonRpcError(error, pResponse);
      return;
   }
   

   // parse
   ClientException ex;
   error = parseClientException(exJson, &ex);
   if (error)
   {
      LOG_ERROR(error);
      json::setJsonRpcError(error, pResponse);
      return;
   }

   // resymbolize the stack
   std::vector<StackElement> stack = s_symbolMaps.resymbolize(ex.stack,
                                                              ex.strongName);

   // build the log message
   bool printFrame = false;
   std::ostringstream ostr;
   BOOST_FOREACH(const StackElement& element, stack)
   {
      // skip past java/lang/Exception entries
      if (!printFrame)
      {
         if (!isExceptionMechanismElement(element))
            printFrame = true;
      }

      if (printFrame)
      {
         ostr << element.fileName << "#" << element.lineNumber
              << "::" << formatMethod(element.methodName)
              << std::endl;
      }
   }

   // form the log entry
   boost::format fmt("CLIENT EXCEPTION (%1%): %2%%3%\n"
                     "%4%"
                     "Client-ID: %5%\n"
                     "User-Agent: %6%");
   std::string logEntry = boost::str(
                        fmt % log::cleanDelims("rsession-" + username)
                            % log::cleanDelims(ex.message)
                            % log::DELIM
                            % log::cleanDelims(ostr.str())
                            % log::cleanDelims(jsonRpcRequest.clientId)
                            % log::cleanDelims(userAgent));

   // log it
   core::system::log(core::system::kLogLevelError, logEntry);


   // set void result
{'fraction_non_alphanumeric': 0.11508433734939759, 'fraction_numerical': 0.003469879518072289, 'mean_word_length': 2.054459817486017, 'pattern_counts': {'":': 2, '<': 57, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6594086', 'n_tokens_mistral': 2955, 'n_tokens_neox': 2863, 'n_words': 623}