Skip to content

Commit

Permalink
Merge branch 'spdlog'
Browse files Browse the repository at this point in the history
  • Loading branch information
overfl0 committed Jan 4, 2018
2 parents 8e6d5ee + c8ab38b commit e18de66
Show file tree
Hide file tree
Showing 61 changed files with 12,185 additions and 201 deletions.
3 changes: 2 additions & 1 deletion PythiaSetPythonPath/PythiaSetPythonPath.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,14 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\src\Logger.h" />
<ClInclude Include="..\src\Paths.h" />
<ClInclude Include="..\src\PythonPath.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\Logger.cpp" />
<ClCompile Include="..\src\PythonPath.cpp" />
<ClCompile Include="..\src\Paths.cpp" />
<ClCompile Include="dllmain.cpp">
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
Expand Down
7 changes: 5 additions & 2 deletions PythiaSetPythonPath/PythiaSetPythonPath.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
<ClInclude Include="..\src\Logger.h">
<Filter>Dependencies</Filter>
</ClInclude>
<ClInclude Include="..\src\Paths.h">
<Filter>Dependencies</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
Expand All @@ -38,10 +41,10 @@
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\PythonPath.cpp">
<ClCompile Include="..\src\Logger.cpp">
<Filter>Dependencies</Filter>
</ClCompile>
<ClCompile Include="..\src\Logger.cpp">
<ClCompile Include="..\src\Paths.cpp">
<Filter>Dependencies</Filter>
</ClCompile>
</ItemGroup>
Expand Down
48 changes: 19 additions & 29 deletions PythiaSetPythonPath/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,21 @@
#include <stdlib.h>
#include <tchar.h>
#include <string>
#include <locale> // wstring_convert
#define LOGGER_FILENAME "PythiaSetPythonPath.log"
#include "../src/Logger.h"
#include "../src/PythonPath.h"
#include "../src/Paths.h"
#include "../src/common.h"

std::wstring pythonPath = L"<Not set>";

std::string w2s(const std::wstring &var)
{
static std::locale loc("");
auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
}
#define LOGGER_FILENAME L"PythiaSetPythonPath.log"

std::wstring s2w(const std::string &var)
{
static std::locale loc("");
auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
}
std::shared_ptr<spdlog::logger> Logger::logfile = getFallbackLogger();
std::wstring pythonPath = L"<Not set>";

void setDLLPath()
{
LOG_INFO("Setting DLL path");
std::wstring pythonPath = getPythonPath();

LOG_INFO(std::string("Setting DLL path to: ") + w2s(pythonPath));
LOG_INFO(std::string("Setting DLL path to: ") + Logger::w2s(pythonPath));
if (SetDllDirectory(pythonPath.c_str()) == 0)
{
LOG_ERROR("Failed to call SetDllDirectory");
Expand Down Expand Up @@ -61,18 +48,21 @@ void __stdcall RVExtensionVersion(char *output, int outputSize)
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
createLogger("PythiaSetPythonPathLogger", LOGGER_FILENAME);
setDLLPath();
LOG_FLUSH();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
LOG_FLUSH();
spdlog::drop_all();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
return TRUE;
}

41 changes: 31 additions & 10 deletions src/EmbeddedPython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
#include "ResponseWriter.h"
#include "SQFReader.h"
#include "SQFWriter.h"
#include "PythonPath.h"
#include "Paths.h"
#include "Modules/pythiainternal.h"
#include "Modules/pythialogger.h"

#define THROW_PYEXCEPTION(_msg_) throw std::runtime_error(_msg_ + std::string(": ") + PyExceptionFetcher().getError());
//#define EXTENSION_DEVELOPMENT 1
Expand Down Expand Up @@ -77,12 +78,14 @@ void EmbeddedPython::DoPythonMagic(std::wstring path)
pythonHomeString = std::vector<wchar_t>(path.begin(), path.end());
pythonHomeString.push_back(0);
Py_SetPythonHome(pythonHomeString.data());
LOG_INFO(std::string("Python home: ") + Logger::w2s(Py_GetPythonHome()));

// Py_SetProgramName(L"D:\\Steam\\steamapps\\common\\Arma 3\\@Pythia\\python-embed-amd64\\python.exe");
std::wstring programName = path + L"\\python.exe"; // Not sure if that should be the value here
programNameString = std::vector<wchar_t>(programName.begin(), programName.end());
programNameString.push_back(0);
Py_SetProgramName(programNameString.data());
LOG_INFO(std::string("Program name: ") + Logger::w2s(Py_GetProgramName()));

/*
Py_SetPath(L"D:\\Steam\\SteamApps\\common\\Arma 3\\@Pythia\\python-embed-amd64\\python35.zip;"
Expand All @@ -94,17 +97,20 @@ void EmbeddedPython::DoPythonMagic(std::wstring path)
path + L"\\python35.zip" + L";" +
path + L"\\DLLs" + L";" +
path + L"\\lib" + L";" +
L""; // Local directory for `python/` directory
getProgramDirectory(); // For `python/` directory access. TODO: Use import hooks for that
pathString = std::vector<wchar_t>(allPaths.begin(), allPaths.end());
pathString.push_back(0);
// Not setting PySetPath overwrites the Py_SetProgramName value (it seems to be ignored then),
Py_SetPath(pathString.data());
LOG_INFO(std::string("Python paths: ") + Logger::w2s(Py_GetPath()));
LOG_INFO(std::string("Current directory: ") + GetCurrentWorkingDir());
}

EmbeddedPython::EmbeddedPython(HMODULE moduleHandle): dllModuleHandle(moduleHandle)
{
DoPythonMagic(getPythonPath());
PyImport_AppendInittab("pythiainternal", PyInit_pythiainternal);
PyImport_AppendInittab("pythialogger", PyInit_pythialogger);
Py_Initialize();
PyEval_InitThreads(); // Initialize and acquire GIL
initialize();
Expand Down Expand Up @@ -242,7 +248,7 @@ void EmbeddedPython::reload()
}
catch (const std::exception& ex)
{
LOG_ERROR("Caught error when reloading the extension: " << ex.what());
LOG_ERROR(std::string("Caught error when reloading the extension: ") + ex.what());
pythonInitializationError = ex.what();
}
}
Expand Down Expand Up @@ -299,22 +305,20 @@ void EmbeddedPython::execute(char *output, int outputSize, const char *input)
reload();
#endif

auto timeStart = std::chrono::high_resolution_clock::now();
if (!pFunc)
{
LOG_ERROR("Calling function {}", input);
throw std::runtime_error("No bootstrapping function. Additional error: " + pythonInitializationError);
}

PyObjectGuard pArgs(SQFReader::decode(input));

/*PyObjectGuard pArgs(PyUnicode_FromString(input));
if (!pArgs)
{
throw std::runtime_error("Failed to transform given input to unicode");
}*/
auto timeDecodeEnded = std::chrono::high_resolution_clock::now();

PyObjectGuard pTuple(PyTuple_Pack(1, pArgs.get()));
if (!pTuple)
{
LOG_ERROR("Calling function {}", input);
throw std::runtime_error("Failed to convert argument string to tuple");
}

Expand All @@ -333,25 +337,32 @@ void EmbeddedPython::execute(char *output, int outputSize, const char *input)
if (overflow == 0 && multipartID >= 0)
{
returnMultipart(multipartID, output, outputSize);
// Do not log multipart requests for performance reasons
return;
}
else
{
LOG_ERROR("Calling function {}", input);
throw std::runtime_error("Could not read the multipart ID");
}
}
else
{
LOG_ERROR("Calling function {}", input);
throw std::runtime_error("Could not get the multipart ID from the request");
}
}
}
else
{
LOG_ERROR("Calling function {}", input);
throw std::runtime_error("Failed to get the function name from the request");
}

auto timeAfterMultipartCheck = std::chrono::high_resolution_clock::now();

PyObjectGuard pResult(PyObject_CallObject(pFunc, pTuple.get()));
auto timeAfterCall = std::chrono::high_resolution_clock::now();
if (pResult)
{
MultipartResponseWriter writer(output, outputSize);
Expand All @@ -361,11 +372,21 @@ void EmbeddedPython::execute(char *output, int outputSize, const char *input)

auto multipartResponse = writer.getMultipart();
handleMultipart(output, outputSize, multipartResponse);
auto timeEnd = std::chrono::high_resolution_clock::now();
LOG_INFO(
"Calling function {}(...). Total: {}us", //, Decoding: {}us, Call: {}us, Encoding: {}us, Multipart: {}us",
PyUnicode_AsUTF8(PyFunction),
(std::chrono::duration_cast<std::chrono::microseconds>(timeEnd - timeStart)).count()/*,
(std::chrono::duration_cast<std::chrono::microseconds>(timeDecodeEnded - timeStart)).count(),
(std::chrono::duration_cast<std::chrono::microseconds>(timeAfterCall - timeAfterMultipartCheck)).count(),
(std::chrono::duration_cast<std::chrono::microseconds>(timeEnd - timeAfterCall)).count(),
(std::chrono::duration_cast<std::chrono::microseconds>(timeAfterMultipartCheck - timeDecodeEnded)).count()*/
);
return;
}
else
{
LOG_ERROR("Calling function {}", input);
THROW_PYEXCEPTION("Failed to execute python extension");
}
}

84 changes: 70 additions & 14 deletions src/Logger.cpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,79 @@
#include "stdafx.h"
#include "Logger.h"
#include <sstream> // stringstream
#include <shlobj.h> // for SHGetFolderPath
#include <string>
#include <memory>
#include <locale> // wstring_convert

#ifndef LOGGER_FILENAME
#define LOGGER_FILENAME "cpythia.log"
#endif
std::shared_ptr<spdlog::logger> getFallbackLogger()
{
constexpr char *fallbackLoggerName = "Fallback_stderr";
spdlog::drop(fallbackLoggerName);
return spdlog::stderr_logger_mt(fallbackLoggerName);
}

std::string Logger::makeFilename()
void createLogger(std::string loggerName, spdlog::filename_t loggerFile)
{
CHAR buffer[MAX_PATH];

if (SUCCEEDED(SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, buffer)))
try
{
spdlog::set_level(spdlog::level::debug);
spdlog::set_sync_mode();
Logger::logfile = spdlog::rotating_logger_mt(loggerName, loggerFile, 1024 * 1024 * 10, 3);
}
catch (const spdlog::spdlog_ex& ex)
{
// Append product-specific path
// TODO: Implement a better way of initializing the logger
return std::string(buffer) + "\\Arma 3\\" + LOGGER_FILENAME;
Logger::logfile = getFallbackLogger();
LOG_ERROR(std::string("Could not create regular logger! ") + ex.what());
}
}

return LOGGER_FILENAME;
// Do NOT call this function in dllmain.cpp!!!
// It creates new threads which is forbidden while attaching the dll
void switchToAsyncLogger(std::string loggerName, spdlog::filename_t loggerFile)
{
LOG_INFO("Switching to asynchronous logger...");
LOG_FLUSH();
Logger::logfile = nullptr;
spdlog::drop(loggerName);

try
{
spdlog::set_level(spdlog::level::debug);
spdlog::set_async_mode(131072, spdlog::async_overflow_policy::block_retry,
nullptr,
std::chrono::milliseconds(500));

Logger::logfile = spdlog::rotating_logger_mt(loggerName, loggerFile, 1024 * 1024 * 10, 3);
LOG_INFO("Switching to asynchronous logger done!");
}
catch (const spdlog::spdlog_ex& ex)
{
// Try creating the regular logger again. Might work.
try
{
createLogger(loggerName, loggerFile);
}
catch (const spdlog::spdlog_ex& ex)
{
Logger::logfile = getFallbackLogger();
LOG_ERROR(std::string("Could not create regular logger! ") + ex.what());
}

LOG_ERROR(std::string("Could not create asynchronous logger! ") + ex.what());
}
}

namespace Logger
{
std::string w2s(const std::wstring &var)
{
static std::locale loc("");
auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
}

std::wstring s2w(const std::string &var)
{
static std::locale loc("");
auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
}
}
Loading

0 comments on commit e18de66

Please sign in to comment.