MXS-1220: Implement JSON diagnostics entry point in first part of filters

First part of the filters now implement the JSON version of the
diagnostics function. The rest are converted in a followup commit.
This commit is contained in:
Markus Mäkelä 2017-04-18 07:15:51 +03:00 committed by Markus Mäkelä
parent 4804c975ad
commit 12baa304e6
16 changed files with 150 additions and 156 deletions

View File

@ -144,10 +144,8 @@ public:
/**
* Called for obtaining diagnostics about the filter session.
*
* @param pDcb The dcb where the diagnostics should be written.
*/
void diagnostics(DCB *pDcb);
json_t* diagnostics();
protected:
FilterSession(MXS_SESSION* pSession);
@ -274,20 +272,24 @@ public:
return rv;
}
static void diagnostics(MXS_FILTER* pInstance, MXS_FILTER_SESSION* pData, DCB* pDcb)
static json_t* diagnostics(MXS_FILTER* pInstance, MXS_FILTER_SESSION* pData)
{
json_t* rval = NULL;
if (pData)
{
FilterSessionType* pFilterSession = static_cast<FilterSessionType*>(pData);
MXS_EXCEPTION_GUARD(pFilterSession->diagnostics(pDcb));
MXS_EXCEPTION_GUARD(rval = pFilterSession->diagnostics());
}
else
{
FilterType* pFilter = static_cast<FilterType*>(pInstance);
MXS_EXCEPTION_GUARD(pFilter->diagnostics(pDcb));
MXS_EXCEPTION_GUARD(rval = pFilter->diagnostics());
}
return rval;
}
static uint64_t getCapabilities(MXS_FILTER* pInstance)

View File

@ -569,8 +569,9 @@ int FilterSession::clientReply(GWBUF* pPacket)
return m_up.clientReply(pPacket);
}
void FilterSession::diagnostics(DCB* pDcb)
json_t* FilterSession::diagnostics()
{
return NULL;
}
}

View File

@ -82,32 +82,9 @@ bool Cache::Create(const CACHE_CONFIG& config,
return pFactory != NULL;
}
void Cache::show(DCB* pDcb) const
json_t* Cache::show() const
{
bool showed = false;
json_t* pInfo = get_info(INFO_ALL);
if (pInfo)
{
size_t flags = JSON_PRESERVE_ORDER;
size_t indent = 2;
char* z = json_dumps(pInfo, JSON_PRESERVE_ORDER | JSON_INDENT(indent));
if (z)
{
dcb_printf(pDcb, "%s\n", z);
free(z);
showed = true;
}
json_decref(pInfo);
}
if (!showed)
{
// So as not to upset anyone expecting a JSON object.
dcb_printf(pDcb, "{\n}\n");
}
return get_info(INFO_ALL);
}
cache_result_t Cache::get_key(const char* zDefault_db,

View File

@ -40,7 +40,7 @@ public:
virtual ~Cache();
void show(DCB* pDcb) const;
json_t* show() const;
const CACHE_CONFIG& config() const
{

View File

@ -18,6 +18,7 @@
#include <maxscale/modulecmd.h>
#include "cachemt.hh"
#include "cachept.hh"
#include "maxscale/jansson.hh"
using std::auto_ptr;
using std::string;
@ -97,7 +98,15 @@ bool cache_command_show(const MODULECMD_ARG* pArgs)
ss_dassert(pFilterDef);
CacheFilter* pFilter = reinterpret_cast<CacheFilter*>(filter_def_get_instance(pFilterDef));
MXS_EXCEPTION_GUARD(pFilter->cache().show(pDcb));
json_t* json = NULL;
MXS_EXCEPTION_GUARD(json = pFilter->cache().show());
if (json)
{
string str = mxs::json_dump(json, JSON_INDENT(4));
dcb_printf(pDcb, "%s\n", str.c_str());
}
return true;
}
@ -297,9 +306,9 @@ CacheFilterSession* CacheFilter::newSession(MXS_SESSION* pSession)
}
// static
void CacheFilter::diagnostics(DCB* pDcb)
json_t* CacheFilter::diagnostics()
{
m_sCache->show(pDcb);
return m_sCache->show();
}
uint64_t CacheFilter::getCapabilities()

View File

@ -37,7 +37,7 @@ public:
CacheFilterSession* newSession(MXS_SESSION* pSession);
void diagnostics(DCB* pDcb);
json_t* diagnostics();
uint64_t getCapabilities();

View File

@ -447,13 +447,13 @@ int CacheFilterSession::clientReply(GWBUF* pData)
return rv;
}
void CacheFilterSession::diagnostics(DCB* pDcb)
json_t* CacheFilterSession::diagnostics()
{
// Not printing anything. Session of the same instance share the same cache, in
// which case the same information would be printed once per session, or all
// threads (but not sessions) share the same cache, in which case the output
// would be nonsensical.
dcb_printf(pDcb, "\n");
return NULL;
}
/**

View File

@ -83,7 +83,7 @@ public:
/**
* Print diagnostics of the session cache.
*/
void diagnostics(DCB *dcb);
json_t* diagnostics();
private:
int handle_expecting_fields();

View File

@ -55,7 +55,7 @@ static void closeSession(MXS_FILTER *instance, MXS_FILTER_SESSION *session);
static void freeSession(MXS_FILTER *instance, MXS_FILTER_SESSION *session);
static void setDownstream(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, MXS_DOWNSTREAM *downstream);
static int routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, GWBUF *queue);
static void diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb);
static json_t* diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession);
static uint64_t getCapabilities(MXS_FILTER* instance);
#define CCR_DEFAULT_TIME "60"
@ -358,28 +358,29 @@ routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *session, GWBUF *queue)
* @param fsession Filter session, may be NULL
* @param dcb The DCB for diagnostic output
*/
static void
diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb)
static json_t* diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession)
{
CCR_INSTANCE *my_instance = (CCR_INSTANCE *)instance;
json_t* rval = json_object();
dcb_printf(dcb, "Configuration:\n\tCount: %d\n", my_instance->count);
dcb_printf(dcb, "\tTime: %d seconds\n", my_instance->time);
json_object_set(rval, "count", json_integer(my_instance->count));
json_object_set(rval, "time", json_integer(my_instance->time));
if (my_instance->match)
{
dcb_printf(dcb, "\tMatch regex: %s\n", my_instance->match);
json_object_set(rval, "match", json_string(my_instance->match));
}
if (my_instance->nomatch)
{
dcb_printf(dcb, "\tExclude regex: %s\n", my_instance->nomatch);
json_object_set(rval, "nomatch", json_string(my_instance->nomatch));
}
dcb_printf(dcb, "\nStatistics:\n");
dcb_printf(dcb, "\tNo. of data modifications: %d\n", my_instance->stats.n_modified);
dcb_printf(dcb, "\tNo. of hints added based on count: %d\n", my_instance->stats.n_add_count);
dcb_printf(dcb, "\tNo. of hints added based on time: %d\n", my_instance->stats.n_add_time);
json_object_set(rval, "data_modifications", json_integer(my_instance->stats.n_modified));
json_object_set(rval, "hints_added_count", json_integer(my_instance->stats.n_add_count));
json_object_set(rval, "hints_added_time", json_integer(my_instance->stats.n_add_time));
return rval;
}
/**

View File

@ -101,7 +101,7 @@ static void closeSession(MXS_FILTER *instance, MXS_FILTER_SESSION *session);
static void freeSession(MXS_FILTER *instance, MXS_FILTER_SESSION *session);
static void setDownstream(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, MXS_DOWNSTREAM *downstream);
static int routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, GWBUF *queue);
static void diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb);
static json_t* diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession);
static uint64_t getCapabilities(MXS_FILTER* instance);
/**
@ -274,19 +274,34 @@ static void rule_free_all(RULE* rule);
static bool process_rule_file(const char* filename, RULE** rules, HASHTABLE **users);
bool replace_rules(FW_INSTANCE* instance);
static void print_rule(RULE *rules, char *dest)
static json_t* rule_to_json(RULE *rule)
{
int type = 0;
if ((int)rules->type > 0 && (int)rules->type < rule_names_len)
if ((int)rule->type > 0 && (int)rule->type < rule_names_len)
{
type = (int)rules->type;
type = (int)rule->type;
}
sprintf(dest, "%s, %s, %d",
rules->name,
rule_names[type],
rules->times_matched);
json_t* rval = json_object();
json_object_set_new(rval, "name", json_string(rule->name));
json_object_set_new(rval, "type", json_string(rule_names[type]));
json_object_set_new(rval, "times_matched", json_integer(rule->times_matched));
return rval;
}
static json_t* rules_to_json(RULE *rules)
{
json_t* rval = json_array();
for (RULE *rule = rules; rule; rule = rule->next)
{
json_array_append(rval, rule_to_json(rule));
}
return rval;
}
/**
@ -751,8 +766,6 @@ bool dbfw_show_rules(const MODULECMD_ARG *argv)
MXS_FILTER_DEF *filter = argv->argv[1].value.filter;
FW_INSTANCE *inst = (FW_INSTANCE*)filter_def_get_instance(filter);
dcb_printf(dcb, "Rule, Type, Times Matched\n");
if (!thr_rules || !thr_users)
{
if (!replace_rules(inst))
@ -761,11 +774,18 @@ bool dbfw_show_rules(const MODULECMD_ARG *argv)
}
}
for (RULE *rule = thr_rules; rule; rule = rule->next)
json_t* json = rules_to_json(thr_rules);
if (json)
{
char buf[strlen(rule->name) + 200]; // Some extra space
print_rule(rule, buf);
dcb_printf(dcb, "%s\n", buf);
char* dump = json_dumps(json, JSON_INDENT(4));
if (dump)
{
dcb_printf(dcb, "%s\n", dump);
}
MXS_FREE(dump);
}
return true;
@ -2483,20 +2503,10 @@ routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *session, GWBUF *queue)
* @param fsession Filter session, may be NULL
* @param dcb The DCB for diagnostic output
*/
static void
diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb)
static json_t*
diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession)
{
FW_INSTANCE *my_instance = (FW_INSTANCE *) instance;
dcb_printf(dcb, "Firewall Filter\n");
dcb_printf(dcb, "Rule, Type, Times Matched\n");
for (RULE *rule = thr_rules; rule; rule = rule->next)
{
char buf[strlen(rule->name) + 200];
print_rule(rule, buf);
dcb_printf(dcb, "%s\n", buf);
}
return rules_to_json(thr_rules);
}
/**

View File

@ -32,7 +32,7 @@ static void closeSession(MXS_FILTER *instance, MXS_FILTER_SESSION *session);
static void freeSession(MXS_FILTER *instance, MXS_FILTER_SESSION *session);
static void setDownstream(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, MXS_DOWNSTREAM *downstream);
static int routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, GWBUF *queue);
static void diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb);
static json_t* diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession);
static uint64_t getCapabilities(MXS_FILTER* instance);
/**
@ -218,20 +218,13 @@ routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *session, GWBUF *queue)
/**
* Diagnostics routine
*
* If fsession is NULL then print diagnostics on the filter
* instance as a whole, otherwise print diagnostics for the
* particular session.
*
* @param instance The filter instance
* @param fsession Filter session, may be NULL
* @param dcb The DCB for diagnostic output
*/
static void
diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb)
static json_t*
diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession)
{
HINT_INSTANCE *my_instance = (HINT_INSTANCE *)instance;
HINT_SESSION *my_session = (HINT_SESSION *)fsession;
return NULL;
}
/**

View File

@ -63,7 +63,7 @@ static void setDownstream(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, M
static void setUpstream(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, MXS_UPSTREAM *upstream);
static int32_t routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, GWBUF *queue);
static int32_t clientReply(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, GWBUF *queue);
static void diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb);
static json_t* diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession);
static uint64_t getCapabilities(MXS_FILTER *instance);
/**
@ -620,13 +620,14 @@ static int32_t routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *session, GWB
*
* This will call the matching diagnostics entry point in the Lua script. If the
* Lua function returns a string, it will be printed to the client DCB.
*
* @param instance The filter instance
* @param fsession Filter session, may be NULL
* @param dcb The DCB for diagnostic output
*/
static void diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb)
static json_t* diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession)
{
LUA_INSTANCE *my_instance = (LUA_INSTANCE *) instance;
LUA_INSTANCE *my_instance = (LUA_INSTANCE *)instance;
json_t* rval = json_object();
if (my_instance)
{
@ -641,27 +642,27 @@ static void diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *
lua_gettop(my_instance->global_lua_state);
if (lua_isstring(my_instance->global_lua_state, -1))
{
dcb_printf(dcb, "%s", lua_tostring(my_instance->global_lua_state, -1));
dcb_printf(dcb, "\n");
json_object_set_new(rval, "script_output",
json_string(lua_tostring(my_instance->global_lua_state, -1)));
}
}
else
{
dcb_printf(dcb, "Global scope call to 'diagnostic' failed: '%s'.\n",
lua_tostring(my_instance->global_lua_state, -1));
lua_pop(my_instance->global_lua_state, -1);
}
spinlock_release(&my_instance->lock);
}
if (my_instance->global_script)
{
dcb_printf(dcb, "Global script: %s\n", my_instance->global_script);
json_object_set_new(rval, "global_script", json_string(my_instance->global_script));
}
if (my_instance->session_script)
{
dcb_printf(dcb, "Session script: %s\n", my_instance->session_script);
json_object_set_new(rval, "session_script", json_string(my_instance->session_script));
}
}
return rval;
}
/**

View File

@ -67,9 +67,8 @@ static int routeQuery(MXS_FILTER *instance,
static int clientReply(MXS_FILTER *instance,
MXS_FILTER_SESSION *sdata,
GWBUF *queue);
static void diagnostics(MXS_FILTER *instance,
MXS_FILTER_SESSION *sdata,
DCB *dcb);
static json_t* diagnostics(MXS_FILTER *instance,
MXS_FILTER_SESSION *sdata);
static uint64_t getCapabilities(MXS_FILTER *instance);
enum maxrows_return_mode
@ -488,12 +487,9 @@ static int clientReply(MXS_FILTER *instance,
* @param fsession Filter session, may be NULL
* @param dcb The DCB for diagnostic output
*/
static void diagnostics(MXS_FILTER *instance, MXS_FILTER_SESSION *sdata, DCB *dcb)
static json_t* diagnostics(MXS_FILTER *instance, MXS_FILTER_SESSION *sdata)
{
MAXROWS_INSTANCE *cinstance = (MAXROWS_INSTANCE*)instance;
MAXROWS_SESSION_DATA *csdata = (MAXROWS_SESSION_DATA*)sdata;
dcb_printf(dcb, "Maxrows filter is working\n");
return NULL;
}

View File

@ -94,7 +94,7 @@ static void setDownstream(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, MX
static void setUpstream(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, MXS_UPSTREAM *upstream);
static int routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, GWBUF *queue);
static int clientReply(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, GWBUF *queue);
static void diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb);
static json_t* diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession);
static uint64_t getCapabilities(MXS_FILTER *instance);
/**
@ -1482,28 +1482,26 @@ static int clientReply(MXS_FILTER* instance, MXS_FILTER_SESSION *session, GWBUF
*
* @param instance The filter instance
* @param fsession Filter session, may be NULL
* @param dcb The DCB for diagnostic output
*/
static void
diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession, DCB *dcb)
static json_t*
diagnostic(MXS_FILTER *instance, MXS_FILTER_SESSION *fsession)
{
MQ_INSTANCE *my_instance = (MQ_INSTANCE *) instance;
MQ_INSTANCE *my_instance = (MQ_INSTANCE*)instance;
json_t* rval = json_object();
if (my_instance)
{
dcb_printf(dcb, "Connecting to [%s]:%d as '%s'.\nVhost: %s\tExchange: %s\nKey: %s\tQueue: %s\n\n",
my_instance->hostname, my_instance->port,
my_instance->username,
my_instance->vhost, my_instance->exchange,
my_instance->key, my_instance->queue
);
dcb_printf(dcb, "%-16s%-16s%-16s\n",
"Messages", "Queued", "Sent");
dcb_printf(dcb, "%-16d%-16d%-16d\n",
my_instance->stats.n_msg,
my_instance->stats.n_queued,
my_instance->stats.n_sent);
}
json_object_set_new(rval, "host", json_string(my_instance->hostname));
json_object_set_new(rval, "user", json_string(my_instance->username));
json_object_set_new(rval, "vhost", json_string(my_instance->vhost));
json_object_set_new(rval, "exchange", json_string(my_instance->exchange));
json_object_set_new(rval, "key", json_string(my_instance->key));
json_object_set_new(rval, "queue", json_string(my_instance->queue));
json_object_set_new(rval, "port", json_integer(my_instance->port));
json_object_set_new(rval, "messages", json_integer(my_instance->stats.n_msg));
json_object_set_new(rval, "queued", json_integer(my_instance->stats.n_queued));
json_object_set_new(rval, "sent", json_integer(my_instance->stats.n_sent));
return rval;
}
/**

View File

@ -311,14 +311,15 @@ RegexHintFilter::create(const char* name, char** options, MXS_CONFIG_PARAMETER*
*
* @param dcb The DCB for diagnostic output
*/
void RegexHintFSession::diagnostics(DCB* dcb)
json_t* RegexHintFSession::diagnostics()
{
m_fil_inst.diagnostics(dcb); /* Print overall diagnostics */
dcb_printf(dcb, "\t\tNo. of queries diverted by filter (session): %d\n",
m_n_diverted);
dcb_printf(dcb, "\t\tNo. of queries not diverted by filter (session): %d\n",
m_n_undiverted);
json_t* rval = m_fil_inst.diagnostics(); /* Print overall diagnostics */
json_object_set_new(rval, "session_queries_diverted", json_integer(m_n_diverted));
json_object_set_new(rval, "session_queries_undiverted", json_integer(m_n_undiverted));
return rval;
}
/**
@ -328,40 +329,45 @@ void RegexHintFSession::diagnostics(DCB* dcb)
*
* @param dcb The DCB for diagnostic output
*/
void RegexHintFilter::diagnostics(DCB* dcb)
json_t* RegexHintFilter::diagnostics()
{
json_t* rval = json_object();
json_object_set_new(rval, "queries_diverted", json_integer(m_total_diverted));
json_object_set_new(rval, "queries_undiverted", json_integer(m_total_undiverted));
if (m_mapping.size() > 0)
{
dcb_printf(dcb, "\t\tMatches and routes:\n");
}
for (unsigned int i = 0; i < m_mapping.size(); i++)
{
dcb_printf(dcb, "\t\t\t/%s/ -> ",
m_mapping[i].m_match.c_str());
dcb_printf(dcb, "%s", m_mapping[i].m_targets[0].c_str());
for (unsigned int j = 1; j < m_mapping[i].m_targets.size(); j++)
json_t* arr = json_array();
for (MappingArray::iterator it = m_mapping.begin(); it != m_mapping.end(); it++)
{
dcb_printf(dcb, ", %s", m_mapping[i].m_targets[j].c_str());
json_t* obj = json_object();
json_t* targets = json_array();
for (StringArray::iterator it2 = it->m_targets.begin(); it2 != it->m_targets.end(); it2++)
{
json_array_append(targets, json_string(it2->c_str()));
}
json_object_set_new(obj, "match", json_string(it->m_match.c_str()));
json_object_set_new(obj, "targets", targets);
}
dcb_printf(dcb, "\n");
json_object_set_new(rval, "mappings", arr);
}
dcb_printf(dcb, "\t\tTotal no. of queries diverted by filter (approx.): %d\n",
m_total_diverted);
dcb_printf(dcb, "\t\tTotal no. of queries not diverted by filter (approx.): %d\n",
m_total_undiverted);
if (m_source)
{
dcb_printf(dcb,
"\t\tReplacement limited to connections from %s\n",
m_source->m_address.c_str());
json_object_set_new(rval, "source", json_string(m_source->m_address.c_str()));
}
if (m_user.length())
{
dcb_printf(dcb,
"\t\tReplacement limit to user %s\n",
m_user.c_str());
json_object_set_new(rval, "user", json_string(m_user.c_str()));
}
return rval;
}
/**

View File

@ -57,7 +57,7 @@ public:
static RegexHintFilter* create(const char* zName, char** pzOptions,
MXS_CONFIG_PARAMETER* ppParams);
RegexHintFSession* newSession(MXS_SESSION *session);
void diagnostics(DCB* dcb);
json_t* diagnostics();
uint64_t getCapabilities();
const RegexToServers* find_servers(char* sql, int sql_len, pcre2_match_data* mdata);
@ -86,7 +86,7 @@ public:
pcre2_match_data* md);
~RegexHintFSession();
void diagnostics(DCB* pDcb);
json_t* diagnostics();
int routeQuery(GWBUF* buffer);
};