190 lines
7.3 KiB
C++
190 lines
7.3 KiB
C++
/* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
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, version 2.0, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
/**
|
|
@brief
|
|
|
|
LOG SINKS: WRITERS
|
|
|
|
There are two types of writers. "Modern services" like the XML or JSON
|
|
writers don't care whether a key/value pair is a table name or an error
|
|
message, or what -- a string is a string. Thus, these services have to
|
|
cover just three cases: format as string, format as integer, or format
|
|
as float. Trivial.
|
|
|
|
The other type is services that write to a fixed format, like the
|
|
traditional MySQL error log. The error log has a timestamp,
|
|
connection ID, severity label, and an error message, in that exact order.
|
|
The traditional error log service therefore doesn't attempt to process
|
|
all the information we might send its way; it just needs to know how to
|
|
retrieve the few items it's interested in, and about printing them in
|
|
the prescribed order. All other information is ignored. Still simple,
|
|
just a different kind of simple.
|
|
|
|
|
|
INPUT
|
|
|
|
So as we've seen, both kinds of writers are quite straightforward.
|
|
It's either "handle 3 storage classes" (which is simple) or "handle as
|
|
many specific item types are you're interested in". The first group
|
|
(which handles any and all items) is actually the simplest, and perhaps
|
|
easier to read and understand than the second group, as they're little
|
|
more than a glorified
|
|
|
|
switch (item->item_class) {
|
|
case STRING: sprintf(buf, "%s", item->value.data_string);
|
|
break;
|
|
case INTEGER: sprintf(buf, "%d", item->value.data_integer);
|
|
break;
|
|
case FLOAT: sprintf(buf, "%f", item->value.data_float);
|
|
break;
|
|
}
|
|
|
|
Anything beyond that in a given source file is usually either
|
|
boilerplate code needed by the component framework (which is
|
|
going to be there no matter how simple or complex our actual
|
|
writer is) or required by the specific output format the sink
|
|
is intended to generate (writing e.g. JSON rows or XML tags,
|
|
escaping characters/entities in string values, indentation,
|
|
and so on).
|
|
|
|
|
|
ERROR MESSAGES THAT AREN'T STRINGS, AND OTHER INSANITY
|
|
|
|
So what if a service is looking for the error message, but it turns
|
|
out that message is not a string?
|
|
|
|
Well, first off, the well-know items (log message, error number, ...)
|
|
all also have a well-known storage class, so an error message for example
|
|
shall always be of string class. Our code (submission API, filter, ...)
|
|
ensures this. Additionally, there is code in the server to help guard
|
|
against broken modules that violate these guarantees, so individual
|
|
loadable services won't have to check that themselves, either.
|
|
|
|
In summary, if a case like that happens, it's a bug, and it's a bug that
|
|
we have tools to detect. The expectation is NOT that services have to
|
|
convert data-types on the fly and be able to handle error messages that
|
|
are numbers, or integers that come wrapped in a string, or any such
|
|
nonsense. It is true that modern writers like XML or JSON gracefully
|
|
handle this case at zero overhead (as they only look at storage class,
|
|
not type or semantics), but this is very specifically NOT required of
|
|
any service.
|
|
*/
|
|
|
|
#ifndef LOG_SERVICE_IMP_H
|
|
#define LOG_SERVICE_IMP_H
|
|
|
|
#include <mysql/components/services/log_service.h>
|
|
#include <mysql/components/services/log_shared.h>
|
|
|
|
extern REQUIRES_SERVICE_PLACEHOLDER(registry);
|
|
|
|
class log_service_imp {
|
|
public:
|
|
/**
|
|
Initialize a loadable logging service.
|
|
*/
|
|
static void init();
|
|
|
|
/**
|
|
De-initialize a loadable logging service.
|
|
*/
|
|
static void exit();
|
|
|
|
public: /* Service Implementations */
|
|
/**
|
|
Have the service process one log line.
|
|
If a run function wishes to itself use error logging
|
|
in case of severe failure, it may do so after FIRST
|
|
securing the all further calls to run() will be rejected.
|
|
"log_sink_test" implements an example of this.
|
|
|
|
@param instance State-pointer that was returned on open.
|
|
@param ll The log_line collection of log_items.
|
|
|
|
@retval <0 an error occurred
|
|
@retval =0 no work was done
|
|
@retval >0 number of processed entities
|
|
*/
|
|
static DEFINE_METHOD(int, run, (void *instance, log_line *ll));
|
|
|
|
/**
|
|
Flush any buffers. This function will be called by the server
|
|
on FLUSH ERROR LOGS. The service may write its buffers, close
|
|
and re-open any log files to work with log-rotation, etc.
|
|
The flush function MUST NOT itself log anything!
|
|
A service implementation may provide a nullptr if it does not
|
|
wish to provide a flush function.
|
|
|
|
@param instance State-pointer that was returned on open.
|
|
Value may be changed in flush.
|
|
|
|
@retval <0 an error occurred
|
|
@retval =0 no work was done
|
|
@retval >0 flush completed without incident
|
|
*/
|
|
static DEFINE_METHOD(int, flush, (void **instance));
|
|
|
|
/**
|
|
Open a new instance.
|
|
|
|
@param ll optional arguments
|
|
@param instance If state is needed, the service may allocate and
|
|
initialize it and return a pointer to it here.
|
|
(This of course is particularly pertinent to
|
|
components that may be opened multiple times,
|
|
such as the JSON log writer.)
|
|
This state is for use of the log-service component
|
|
in question only and can take any layout suitable
|
|
to that component's need. The state is opaque to
|
|
the server/logging framework. It must be released
|
|
on close.
|
|
|
|
@retval <0 a new instance could not be created
|
|
@retval =0 success, returned hande is valid
|
|
*/
|
|
static DEFINE_METHOD(int, open, (log_line * ll, void **instance));
|
|
|
|
/**
|
|
Close and release an instance. Flushes any buffers.
|
|
|
|
@param instance State-pointer that was returned on open.
|
|
If memory was allocated for this state,
|
|
it should be released, and the pointer
|
|
set to nullptr.
|
|
|
|
@retval <0 an error occurred
|
|
@retval =0 success
|
|
*/
|
|
static DEFINE_METHOD(int, close, (void **instance));
|
|
|
|
/**
|
|
Get characteristics of a log-service.
|
|
|
|
@retval <0 an error occurred
|
|
@retval >=0 characteristics (a set of log_service_chistics flags)
|
|
*/
|
|
static DEFINE_METHOD(int, characteristics, (void));
|
|
};
|
|
|
|
#endif /* LOG_SERVICE_IMP_H */
|