Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lua: support logging methods on all envoy lua objects #37293

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ new_features:
:ref:`%COMMON_DURATION% <config_access_log_format_common_duration>` access log
formatter operator. The following time points were added: ``%US_CX_BEG%``,
``%US_CX_END%``, ``%US_HS_END%``.
- area: lua
change: |
Add logging functions to all lua objects. Previously these were only available on the Lua http filter request handle.
- area: access log
change: |
Added fields for :ref:`DOWNSTREAM_DIRECT_LOCAL_ADDRESS and DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT <config_access_log_format>`.
Expand Down
15 changes: 15 additions & 0 deletions docs/root/_include/lua_common.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
``log*()``
^^^^^^^^^^

.. code-block:: lua

handle:logTrace(message)
handle:logDebug(message)
handle:logInfo(message)
handle:logWarn(message)
handle:logErr(message)
handle:logCritical(message)

Logs a message using Envoy's application logging. *message* is a string to log.

These are supported on all objects that Envoy exposes to Lua.
5 changes: 5 additions & 0 deletions docs/root/configuration/http/cluster_specifier/lua.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ Returns a :ref:`header object <config_lua_cluster_specifier_header_wrapper>`.

Returns a :ref:`handle <config_lua_cluster_specifier_cluster>` to the specified cluster, or nil if it isn't found.

.. include:: ../../../_include/lua_common.rst

.. _config_lua_cluster_specifier_header_wrapper:

Header object API
Expand All @@ -100,6 +102,8 @@ Returns either a string containing the header value, or ``nil`` if the header do

If there are multiple headers in the same case-insensitive key, their values will be concatenated to a string separated by ``,``.

.. include:: ../../../_include/lua_common.rst

.. _config_lua_cluster_specifier_cluster:

Cluster API
Expand Down Expand Up @@ -132,3 +136,4 @@ This method gets the current number of requests for this cluster.

This method gets the current number of pending requests for this cluster.

.. include:: ../../../_include/lua_common.rst
32 changes: 19 additions & 13 deletions docs/root/configuration/http/http_filters/lua_filter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -372,19 +372,7 @@ to the next filter.

Returns a :ref:`header object <config_http_filters_lua_header_wrapper>`.

``log*()``
^^^^^^^^^^

.. code-block:: lua

handle:logTrace(message)
handle:logDebug(message)
handle:logInfo(message)
handle:logWarn(message)
handle:logErr(message)
handle:logCritical(message)

Logs a message using Envoy's application logging. *message* is a string to log.
.. include:: ../../../_include/lua_common.rst

``httpCall()``
^^^^^^^^^^^^^^
Expand Down Expand Up @@ -624,6 +612,8 @@ Default resolution is millisecond if *resolution* is not set.
Header object API
-----------------

.. include:: ../../../_include/lua_common.rst

``add()``
^^^^^^^^^

Expand Down Expand Up @@ -720,6 +710,8 @@ effects HTTP/1 connections. It will have no effect if the client is HTTP/2 or HT
Buffer API
----------

.. include:: ../../../_include/lua_common.rst

``length()``
^^^^^^^^^^^^

Expand Down Expand Up @@ -757,6 +749,8 @@ Set the content of wrapped buffer with the input string.
Metadata object API
-------------------

.. include:: ../../../_include/lua_common.rst

``get()``
^^^^^^^^^

Expand Down Expand Up @@ -784,6 +778,8 @@ key. *value* is a *metadata* entry value.
Stream info object API
-----------------------

.. include:: ../../../_include/lua_common.rst

``protocol()``
^^^^^^^^^^^^^^

Expand Down Expand Up @@ -878,6 +874,8 @@ Returns the string representation of :repo:`requested server name <envoy/stream_
Connection stream info object API
---------------------------------

.. include:: ../../../_include/lua_common.rst

``dynamicMetadata()``
^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -890,6 +888,8 @@ Returns a :ref:`dynamic metadata object <config_http_filters_lua_stream_info_dyn
Dynamic metadata object API
---------------------------

.. include:: ../../../_include/lua_common.rst

``get()``
^^^^^^^^^

Expand Down Expand Up @@ -947,6 +947,8 @@ key. *value* is a *dynamicMetadata* entry value.
Connection object API
---------------------

.. include:: ../../../_include/lua_common.rst

``ssl()``
^^^^^^^^^

Expand All @@ -968,6 +970,8 @@ Returns an :ref:`SSL connection info object <config_http_filters_lua_ssl_socket_
SSL connection object API
-------------------------

.. include:: ../../../_include/lua_common.rst

``peerCertificatePresented()``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -1219,6 +1223,8 @@ Returns the TLS version (e.g., TLSv1.2, TLSv1.3) used in the established TLS con
Parsed name object API
----------------------

.. include:: ../../../_include/lua_common.rst

``commonName()``
^^^^^^^^^^^^^^^^

Expand Down
28 changes: 28 additions & 0 deletions source/extensions/filters/common/lua/lua.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,34 @@ namespace Filters {
namespace Common {
namespace Lua {

void LuaLoggable::scriptLog(spdlog::level::level_enum level, absl::string_view message) {
switch (level) {
case spdlog::level::trace:
ENVOY_LOG(trace, "script log: {}", message);
return;
case spdlog::level::debug:
ENVOY_LOG(debug, "script log: {}", message);
return;
case spdlog::level::info:
ENVOY_LOG(info, "script log: {}", message);
return;
case spdlog::level::warn:
ENVOY_LOG(warn, "script log: {}", message);
return;
case spdlog::level::err:
ENVOY_LOG(error, "script log: {}", message);
return;
case spdlog::level::critical:
ENVOY_LOG(critical, "script log: {}", message);
return;
case spdlog::level::off:
PANIC("unsupported");
return;
case spdlog::level::n_levels:
PANIC("unsupported");
}
}

Coroutine::Coroutine(const std::pair<lua_State*, lua_State*>& new_thread_state)
: coroutine_state_(new_thread_state, false) {}

Expand Down
72 changes: 69 additions & 3 deletions source/extensions/filters/common/lua/lua.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ template <typename T> inline T* allocateLuaUserData(lua_State* state) {
return alignAndCast<T>(mem);
}

class LuaLoggable : public Logger::Loggable<Logger::Id::lua> {
public:
void scriptLog(spdlog::level::level_enum level, absl::string_view message);
};

/**
* This is the base class for all C++ objects that we expose out to Lua. The goal is to hide as
* much ugliness as possible. In general, to use this, do the following:
Expand All @@ -128,9 +133,10 @@ template <typename T> inline T* allocateLuaUserData(lua_State* state) {
* owned by Lua*. Lua can GC it at any time. If you want to make sure that does not happen, you
* must hold a ref to it in C++, generally via LuaRef or LuaDeathRef.
*/
template <class T> class BaseLuaObject : protected Logger::Loggable<Logger::Id::lua> {
template <class T> class BaseLuaObject : public LuaLoggable {
public:
using ExportedFunctions = std::vector<std::pair<const char*, lua_CFunction>>;
using ExportedFunction = std::pair<const char*, lua_CFunction>;
using ExportedFunctions = std::vector<ExportedFunction>;

virtual ~BaseLuaObject() = default;

Expand All @@ -155,12 +161,25 @@ template <class T> class BaseLuaObject : protected Logger::Loggable<Logger::Id::
* @param state supplies the state to register with.
*/
static void registerType(lua_State* state) {
constexpr std::array log_functions{
ExportedFunction{"logTrace", static_luaLogTrace},
ExportedFunction{"logDebug", static_luaLogDebug},
ExportedFunction{"logInfo", static_luaLogInfo},
ExportedFunction{"logWarn", static_luaLogWarn},
ExportedFunction{"logErr", static_luaLogErr},
ExportedFunction{"logCritical", static_luaLogCritical},
};

std::vector<luaL_Reg> to_register;

for (auto& function : log_functions) {
to_register.push_back({function.first, function.second});
}

// Fetch all of the functions to be exported to Lua so that we can register them in the
// metatable.
ExportedFunctions functions = T::exportedFunctions();
for (auto function : functions) {
for (auto& function : functions) {
to_register.push_back({function.first, function.second});
}

Expand Down Expand Up @@ -236,9 +255,56 @@ template <class T> class BaseLuaObject : protected Logger::Loggable<Logger::Id::
virtual void onMarkLive() {}

private:
/**
* Log a message to the Envoy log.
* @param 1 (string): The log message.
*/
DECLARE_LUA_FUNCTION(T, luaLogTrace);
DECLARE_LUA_FUNCTION(T, luaLogDebug);
DECLARE_LUA_FUNCTION(T, luaLogInfo);
DECLARE_LUA_FUNCTION(T, luaLogWarn);
DECLARE_LUA_FUNCTION(T, luaLogErr);
DECLARE_LUA_FUNCTION(T, luaLogCritical);

bool dead_{};
};

template <class T> int BaseLuaObject<T>::luaLogTrace(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
scriptLog(spdlog::level::trace, message);
return 0;
}

template <class T> int BaseLuaObject<T>::luaLogDebug(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
scriptLog(spdlog::level::debug, message);
return 0;
}

template <class T> int BaseLuaObject<T>::luaLogInfo(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
scriptLog(spdlog::level::info, message);
return 0;
}

template <class T> int BaseLuaObject<T>::luaLogWarn(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
scriptLog(spdlog::level::warn, message);
return 0;
}

template <class T> int BaseLuaObject<T>::luaLogErr(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
scriptLog(spdlog::level::err, message);
return 0;
}

template <class T> int BaseLuaObject<T>::luaLogCritical(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
scriptLog(spdlog::level::critical, message);
return 0;
}

/**
* This is basically a Lua smart pointer. The idea is that given a Lua object, if we want to
* guarantee that Lua won't destroy it, we need to reference it. This wraps the reference
Expand Down
64 changes: 0 additions & 64 deletions source/extensions/filters/http/lua/lua_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -657,42 +657,6 @@ int StreamHandleWrapper::luaConnection(lua_State* state) {
return 1;
}

int StreamHandleWrapper::luaLogTrace(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
filter_.scriptLog(spdlog::level::trace, message);
return 0;
}

int StreamHandleWrapper::luaLogDebug(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
filter_.scriptLog(spdlog::level::debug, message);
return 0;
}

int StreamHandleWrapper::luaLogInfo(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
filter_.scriptLog(spdlog::level::info, message);
return 0;
}

int StreamHandleWrapper::luaLogWarn(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
filter_.scriptLog(spdlog::level::warn, message);
return 0;
}

int StreamHandleWrapper::luaLogErr(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
filter_.scriptLog(spdlog::level::err, message);
return 0;
}

int StreamHandleWrapper::luaLogCritical(lua_State* state) {
absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2);
filter_.scriptLog(spdlog::level::critical, message);
return 0;
}

int StreamHandleWrapper::luaVerifySignature(lua_State* state) {
// Step 1: Get hash function.
absl::string_view hash = luaL_checkstring(state, 2);
Expand Down Expand Up @@ -935,34 +899,6 @@ void Filter::scriptError(const Filters::Common::Lua::LuaException& e) {
response_stream_wrapper_.reset();
}

void Filter::scriptLog(spdlog::level::level_enum level, absl::string_view message) {
switch (level) {
case spdlog::level::trace:
ENVOY_LOG(trace, "script log: {}", message);
return;
case spdlog::level::debug:
ENVOY_LOG(debug, "script log: {}", message);
return;
case spdlog::level::info:
ENVOY_LOG(info, "script log: {}", message);
return;
case spdlog::level::warn:
ENVOY_LOG(warn, "script log: {}", message);
return;
case spdlog::level::err:
ENVOY_LOG(error, "script log: {}", message);
return;
case spdlog::level::critical:
ENVOY_LOG(critical, "script log: {}", message);
return;
case spdlog::level::off:
PANIC("unsupported");
return;
case spdlog::level::n_levels:
PANIC("unsupported");
}
}

void Filter::DecoderCallbacks::respond(Http::ResponseHeaderMapPtr&& headers, Buffer::Instance* body,
lua_State*) {
uint64_t status = Http::Utility::getResponseStatus(*headers);
Expand Down
Loading