Commit 3f255881 authored by unknown's avatar unknown

WL#2299, structured log events

parent 0eb1a810
......@@ -688,7 +688,8 @@ INCLUDE_FILE_PATTERNS =
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed.
PREDEFINED = DOXYGEN_SHOULD_SKIP_DEPRECATED \
PREDEFINED = DOXYGEN_FIX \
DOXYGEN_SHOULD_SKIP_DEPRECATED \
DOXYGEN_SHOULD_SKIP_INTERNAL \
protected=private
......
/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <mysql.h>
#include <ndbapi/NdbApi.hpp>
#include <mgmapi.h>
#include <stdio.h>
/*
* export LD_LIBRARY_PATH=../../../libmysql_r/.libs:../../../ndb/src/.libs
*/
#define MGMERROR(h) \
{ \
fprintf(stderr, "code: %d msg: %s\n", \
ndb_mgm_get_latest_error(h), \
ndb_mgm_get_latest_error_msg(h)); \
exit(-1); \
}
#define LOGEVENTERROR(h) \
{ \
fprintf(stderr, "code: %d msg: %s\n", \
ndb_logevent_get_latest_error(h), \
ndb_logevent_get_latest_error_msg(h)); \
exit(-1); \
}
int main()
{
NdbMgmHandle h;
NdbLogEventHandle l;
int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 };
struct ndb_logevent event;
ndb_init();
h= ndb_mgm_create_handle();
if ( h == 0)
{
printf("Unable to create handle\n");
exit(-1);
}
if (ndb_mgm_connect(h,0,0,0)) MGMERROR(h);
l= ndb_mgm_create_logevent_handle(h, filter);
if ( l == 0 ) MGMERROR(h);
while (1)
{
int timeout= 5000;
int r= ndb_logevent_get_next(l,&event,timeout);
if (r == 0)
printf("No event within %d milliseconds\n", timeout);
else if (r < 0)
LOGEVENTERROR(l)
else
{
printf("Event %d from node ID %d\n",
event.type,
event.source_nodeid);
printf("Category %d, severity %d, level %d\n",
event.category,
event.severity,
event.level);
switch (event.type) {
case NDB_LE_BackupStarted:
printf("BackupStartded\n");
printf("Starting node ID: %d\n", event.BackupStarted.starting_node);
printf("Backup ID: %d\n", event.BackupStarted.backup_id);
break;
case NDB_LE_BackupCompleted:
printf("BackupCompleted\n");
printf("Backup ID: %d\n", event.BackupStarted.backup_id);
break;
case NDB_LE_BackupAborted:
break;
case NDB_LE_BackupFailedToStart:
break;
default:
printf("Unexpected event\n");
break;
}
}
}
ndb_mgm_destroy_logevent_handle(&l);
ndb_mgm_destroy_handle(&h);
ndb_end(0);
return 0;
}
......@@ -17,12 +17,12 @@
#ifndef EVENTLOGGER_H
#define EVENTLOGGER_H
#include <Logger.hpp>
#include <FileLogHandler.hpp>
#include <GrepError.hpp>
#include <kernel_types.h>
#include <logger/Logger.hpp>
#include <logger/FileLogHandler.hpp>
#include "GrepError.hpp"
#include <kernel/kernel_types.h>
#include <kernel/LogLevel.hpp>
#include <signaldata/EventReport.hpp>
#include <kernel/signaldata/EventReport.hpp>
class EventLoggerBase {
public:
......@@ -39,11 +39,14 @@ public:
* threshold - is in range [0-15]
* severity - DEBUG to ALERT (Type of log message)
*/
typedef void (* EventTextFunction)(char *,size_t,const Uint32*);
struct EventRepLogLevelMatrix {
Ndb_logevent_type eventType;
LogLevel::EventCategory eventCategory;
Uint32 threshold;
Logger::LoggerLevel severity;
Ndb_logevent_type eventType;
LogLevel::EventCategory eventCategory;
Uint32 threshold;
Logger::LoggerLevel severity;
EventTextFunction textF;
};
static const EventRepLogLevelMatrix matrix[];
......@@ -51,7 +54,8 @@ public:
static int event_lookup(int eventType,
LogLevel::EventCategory &cat,
Uint32 &threshold,
Logger::LoggerLevel &severity);
Logger::LoggerLevel &severity,
EventTextFunction &textF);
};
/**
......@@ -130,17 +134,18 @@ public:
* @param nodeId the node id of event origin.
*/
virtual void log(int, const Uint32*, NodeId = 0,const class LogLevel * = 0);
/**
* Returns the event text for the specified event report type.
*
* @param type the event type.
* @param textF print function for the event
* @param theData the event data.
* @param nodeId a node id.
* @return the event report text.
*/
static const char* getText(char * dst, size_t dst_len,
int type,
EventTextFunction textF,
const Uint32* theData, NodeId nodeId = 0);
/**
......
......@@ -147,7 +147,7 @@ LogLevel::set_max(const LogLevel & org){
return * this;
}
#include <signaldata/EventSubscribeReq.hpp>
#include "signaldata/EventSubscribeReq.hpp"
inline
LogLevel&
......
......@@ -18,8 +18,8 @@
#define SIGNAL_DATA_H
#include <ndb_global.h>
#include <ndb_limits.h>
#include <kernel_types.h>
#include <kernel/ndb_limits.h>
#include <kernel/kernel_types.h>
#include <BaseString.hpp>
#define ASSERT_BOOL(flag, message) assert(flag<=1)
......
......@@ -86,6 +86,53 @@
* int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 };
* int fd = ndb_mgm_listen_event(handle, filter);
* @endcode
*
*
* @section secSLogEvents Structured Log Events
*
* The following steps are involved:
* - Create a NdbEventLogHandle using ndb_mgm_create_logevent_handle()
* - Wait and store log events using ndb_logevent_get_next()
* - The log event data is available in the struct ndb_logevent. The
* data which is specific to a particular event is stored in a union
* between structs so use ndb_logevent::type to decide which struct
* is valid.
*
* Sample code for listening to Backup related events. The availaable log
* events are listed in @ref ndb_logevent.h
*
* @code
* int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 };
* NdbEventLogHandle le_handle= ndb_mgm_create_logevent_handle(handle, filter);
* struct ndb_logevent le;
* int r= ndb_logevent_get_next(le_handle,&le,0);
* if (r < 0) error
* else if (r == 0) no event
*
* switch (le.type)
* {
* case NDB_LE_BackupStarted:
* ... le.BackupStarted.starting_node;
* ... le.BackupStarted.backup_id;
* break;
* case NDB_LE_BackupFailedToStart:
* ... le.BackupFailedToStart.error;
* break;
* case NDB_LE_BackupCompleted:
* ... le.BackupCompleted.stop_gci;
* break;
* case NDB_LE_BackupAborted:
* ... le.BackupStarted.backup_id;
* break;
* default:
* break;
* }
* @endcode
*/
/*
* @page ndb_logevent.h ndb_logevent.h
* @include ndb_logevent.h
*/
/** @addtogroup MGM_C_API
......@@ -93,6 +140,7 @@
*/
#include <ndb_types.h>
#include "ndb_logevent.h"
#include "mgmapi_config_parameters.h"
#ifdef __cplusplus
......@@ -348,97 +396,6 @@ extern "C" {
};
#endif
/**
* Log event severities (used to filter the cluster log,
* ndb_mgm_set_clusterlog_severity_filter(), and filter listening to events
* ndb_mgm_listen_event())
*/
enum ndb_mgm_event_severity {
NDB_MGM_ILLEGAL_EVENT_SEVERITY = -1,
/* Must be a nonnegative integer (used for array indexing) */
/** Cluster log on */
NDB_MGM_EVENT_SEVERITY_ON = 0,
/** Used in NDB Cluster developement */
NDB_MGM_EVENT_SEVERITY_DEBUG = 1,
/** Informational messages*/
NDB_MGM_EVENT_SEVERITY_INFO = 2,
/** Conditions that are not error condition, but might require handling.
*/
NDB_MGM_EVENT_SEVERITY_WARNING = 3,
/** Conditions that, while not fatal, should be corrected. */
NDB_MGM_EVENT_SEVERITY_ERROR = 4,
/** Critical conditions, like device errors or out of resources */
NDB_MGM_EVENT_SEVERITY_CRITICAL = 5,
/** A condition that should be corrected immediately,
* such as a corrupted system
*/
NDB_MGM_EVENT_SEVERITY_ALERT = 6,
/* must be next number, works as bound in loop */
/** All severities */
NDB_MGM_EVENT_SEVERITY_ALL = 7
};
/**
* Log event categories, used to set filter level on the log events using
* ndb_mgm_set_clusterlog_loglevel() and ndb_mgm_listen_event()
*/
enum ndb_mgm_event_category {
/**
* Invalid log event category
*/
NDB_MGM_ILLEGAL_EVENT_CATEGORY = -1,
/**
* Log events during all kinds of startups
*/
NDB_MGM_EVENT_CATEGORY_STARTUP = CFG_LOGLEVEL_STARTUP,
/**
* Log events during shutdown
*/
NDB_MGM_EVENT_CATEGORY_SHUTDOWN = CFG_LOGLEVEL_SHUTDOWN,
/**
* Statistics log events
*/
NDB_MGM_EVENT_CATEGORY_STATISTIC = CFG_LOGLEVEL_STATISTICS,
/**
* Log events related to checkpoints
*/
NDB_MGM_EVENT_CATEGORY_CHECKPOINT = CFG_LOGLEVEL_CHECKPOINT,
/**
* Log events during node restart
*/
NDB_MGM_EVENT_CATEGORY_NODE_RESTART = CFG_LOGLEVEL_NODERESTART,
/**
* Log events related to connections between cluster nodes
*/
NDB_MGM_EVENT_CATEGORY_CONNECTION = CFG_LOGLEVEL_CONNECTION,
/**
* Backup related log events
*/
NDB_MGM_EVENT_CATEGORY_BACKUP = CFG_LOGLEVEL_BACKUP,
/**
* Congestion related log events
*/
NDB_MGM_EVENT_CATEGORY_CONGESTION = CFG_LOGLEVEL_CONGESTION,
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Loglevel debug
*/
NDB_MGM_EVENT_CATEGORY_DEBUG = CFG_LOGLEVEL_DEBUG,
#endif
/**
* Uncategorized log events (severity info)
*/
NDB_MGM_EVENT_CATEGORY_INFO = CFG_LOGLEVEL_INFO,
/**
* Uncategorized log events (severity warning or higher)
*/
NDB_MGM_EVENT_CATEGORY_ERROR = CFG_LOGLEVEL_ERROR,
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
NDB_MGM_MIN_EVENT_CATEGORY = CFG_MIN_LOGLEVEL,
NDB_MGM_MAX_EVENT_CATEGORY = CFG_MAX_LOGLEVEL
#endif
};
/***************************************************************************/
/**
* @name Functions: Error Handling
......@@ -871,6 +828,64 @@ extern "C" {
struct ndb_mgm_reply* reply);
#endif
/**
* The NdbLogEventHandle
*/
typedef struct ndb_logevent_handle * NdbLogEventHandle;
/**
* Listen to log events.
*
* @param handle NDB management handle.
* @param filter pairs of { level, ndb_mgm_event_category } that will be
* pushed to fd, level=0 ends list.
*
* @return NdbLogEventHandle
*/
NdbLogEventHandle ndb_mgm_create_logevent_handle(NdbMgmHandle,
const int filter[]);
void ndb_mgm_destroy_logevent_handle(NdbLogEventHandle*);
/**
* Retrieve filedescriptor from NdbLogEventHandle. May be used in
* e.g. an application select() statement.
*
* @note Do not attemt to read from it, it will corrupt the parsing.
*
* @return filedescriptor, -1 on failure.
*/
int ndb_logevent_get_fd(const NdbLogEventHandle);
/**
* Attempt to retrieve next log event and will fill in the supplied
* struct dst
*
* @param dst Pointer to struct to fill in event information
* @param timeout_in_milliseconds Timeout for waiting for event
*
* @return >0 if event exists, 0 no event (timed out), or -1 on error.
*
* @note Return value <=0 will leave dst untouched
*/
int ndb_logevent_get_next(const NdbLogEventHandle,
struct ndb_logevent *dst,
unsigned timeout_in_milliseconds);
/**
* Retrieve laterst error code
*
* @return error code
*/
int ndb_logevent_get_latest_error(const NdbLogEventHandle);
/**
* Retrieve laterst error message
*
* @return error message
*/
const char *ndb_logevent_get_latest_error_msg(const NdbLogEventHandle);
/** @} *********************************************************************/
/**
* @name Functions: Backup
......
This diff is collapsed.
This diff is collapsed.
......@@ -198,7 +198,8 @@ void Cmvmi::execEVENT_REP(Signal* signal)
Uint32 threshold;
LogLevel::EventCategory eventCategory;
Logger::LoggerLevel severity;
if (EventLoggerBase::event_lookup(eventType,eventCategory,threshold,severity))
EventLoggerBase::EventTextFunction textF;
if (EventLoggerBase::event_lookup(eventType,eventCategory,threshold,severity,textF))
return;
SubscriberPtr ptr;
......
noinst_LTLIBRARIES = libmgmapi.la
libmgmapi_la_SOURCES = mgmapi.cpp mgmapi_configuration.cpp LocalConfig.cpp
libmgmapi_la_SOURCES = mgmapi.cpp ndb_logevent.cpp mgmapi_configuration.cpp LocalConfig.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/include/mgmapi
......
......@@ -22,8 +22,8 @@
#include <NdbSleep.h>
#include <NdbTCP.h>
#include "mgmapi.h"
#include "mgmapi_debug.h"
#include <mgmapi.h>
#include <mgmapi_debug.h>
#include "mgmapi_configuration.hpp"
#include <socket_io.h>
......@@ -1156,9 +1156,9 @@ ndb_mgm_set_loglevel_node(NdbMgmHandle handle, int nodeId,
return 0;
}
extern "C"
int
ndb_mgm_listen_event(NdbMgmHandle handle, const int filter[])
ndb_mgm_listen_event_internal(NdbMgmHandle handle, const int filter[],
int structured)
{
SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_listen_event");
const ParserRow<ParserDummy> stat_reply[] = {
......@@ -1180,6 +1180,8 @@ ndb_mgm_listen_event(NdbMgmHandle handle, const int filter[])
}
Properties args;
args.put("structured", structured);
{
BaseString tmp;
for(int i = 0; filter[i] != 0; i += 2){
......@@ -1203,6 +1205,13 @@ ndb_mgm_listen_event(NdbMgmHandle handle, const int filter[])
return sockfd;
}
extern "C"
int
ndb_mgm_listen_event(NdbMgmHandle handle, const int filter[])
{
return ndb_mgm_listen_event_internal(handle,filter,0);
}
extern "C"
int
ndb_mgm_get_stat_port(NdbMgmHandle handle, struct ndb_mgm_reply* /*reply*/)
......@@ -2138,5 +2147,4 @@ ndb_mgm_get_connection_int_parameter(NdbMgmHandle handle,
DBUG_RETURN(res);
}
template class Vector<const ParserRow<ParserDummy>*>;
/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef MGMAPI_CONFIGURATION_HPP
#define MGMAPI_CONFIGURATION_HPP
......
This diff is collapsed.
/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef NDB_LOGEVENT_HPP
#define NDB_LOGEVENT_HPP
#include <ndb_logevent.h>
struct Ndb_logevent_body_row {
enum Ndb_logevent_type type; // type
const char *token; // token to use for text transfer
int index; // index into theData array
int (*index_fn)(int); // conversion function on the data array[index]
int offset; // offset into struct ndb_logevent
int size; // offset into struct ndb_logevent
};
extern
struct Ndb_logevent_body_row ndb_logevent_body[];
#endif
......@@ -49,6 +49,7 @@ class Ndb_mgmd_event_service : public EventLoggerBase
public:
struct Event_listener : public EventLoggerBase {
NDB_SOCKET_TYPE m_socket;
Uint32 m_parsable;
};
private:
......
......@@ -31,6 +31,7 @@
#include <mgmapi_configuration.hpp>
#include <Vector.hpp>
#include "Services.hpp"
#include "../mgmapi/ndb_logevent.hpp"
extern bool g_StopServer;
......@@ -256,6 +257,7 @@ ParserRow<MgmApiSession> commands[] = {
MGM_CMD("listen event", &MgmApiSession::listen_event, ""),
MGM_ARG("node", Int, Optional, "Node"),
MGM_ARG("parsable", Int, Optional, "Parsable"),
MGM_ARG("filter", String, Mandatory, "Event category"),
MGM_CMD("purge stale sessions", &MgmApiSession::purge_stale_sessions, ""),
......@@ -1249,25 +1251,49 @@ Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId)
Uint32 threshold;
LogLevel::EventCategory cat;
Logger::LoggerLevel severity;
EventLoggerBase::EventTextFunction textF;
int i;
DBUG_ENTER("Ndb_mgmd_event_service::log");
DBUG_PRINT("enter",("eventType=%d, nodeid=%d", eventType, nodeId));
if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity))
if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity,textF))
DBUG_VOID_RETURN;
char m_text[256];
EventLogger::getText(m_text, sizeof(m_text), eventType, theData, nodeId);
EventLogger::getText(m_text, sizeof(m_text),
textF, theData, nodeId);
BaseString str("log event reply\n");
str.appfmt("type=%d\n", eventType);
str.appfmt("time=%d\n", 0);
str.appfmt("source_nodeid=%d\n", nodeId);
for (i= 0; ndb_logevent_body[i].token; i++)
{
if ( ndb_logevent_body[i].type != eventType)
continue;
int val= theData[ndb_logevent_body[i].index];
if (ndb_logevent_body[i].index_fn)
val= (*(ndb_logevent_body[i].index_fn))(val);
str.appfmt("%s=%d\n",ndb_logevent_body[i].token, val);
}
Vector<NDB_SOCKET_TYPE> copy;
Vector<NDB_SOCKET_TYPE> copy;
m_clients.lock();
for(i = m_clients.size() - 1; i >= 0; i--){
if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat)){
if(m_clients[i].m_socket != NDB_INVALID_SOCKET &&
println_socket(m_clients[i].m_socket,
MAX_WRITE_TIMEOUT, m_text) == -1){
copy.push_back(m_clients[i].m_socket);
m_clients.erase(i, false);
if(m_clients[i].m_socket != NDB_INVALID_SOCKET)
{
int r;
if (m_clients[i].m_parsable)
r= println_socket(m_clients[i].m_socket,
MAX_WRITE_TIMEOUT, str.c_str());
else
r= println_socket(m_clients[i].m_socket,
MAX_WRITE_TIMEOUT, m_text);
if (r == -1) {
copy.push_back(m_clients[i].m_socket);
m_clients.erase(i, false);
}
}
}
}
......@@ -1395,15 +1421,17 @@ MgmApiSession::getConnectionParameter(Parser_t::Context &ctx,
void
MgmApiSession::listen_event(Parser<MgmApiSession>::Context & ctx,
Properties const & args) {
Uint32 parsable= 0;
BaseString node, param, value;
args.get("node", node);
args.get("filter", param);
args.get("parsable", &parsable);
int result = 0;
BaseString msg;
Ndb_mgmd_event_service::Event_listener le;
le.m_parsable = parsable;
le.m_socket = m_socket;
Vector<BaseString> list;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment