Skip to content

Commit

Permalink
Set logger for driver API (#1107)
Browse files Browse the repository at this point in the history
  • Loading branch information
yitam authored Mar 25, 2020
1 parent fb335c0 commit 7214e8d
Show file tree
Hide file tree
Showing 20 changed files with 434 additions and 123 deletions.
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ jobs:
docker pull mcr.microsoft.com/mssql/server:2017-latest
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=$(pwd)' -p 1433:1433 -h $(host) --name=$(host) -d mcr.microsoft.com/mssql/server:2017-latest
docker ps -a
sleep 5
sleep 10
docker exec -t $(host) /opt/mssql-tools/bin/sqlcmd -S $(server) -U $(uid) -P $(pwd) -Q 'select @@Version'
displayName: 'Run SQL Server for Linux'
Expand Down
21 changes: 4 additions & 17 deletions source/pdo_sqlsrv/pdo_dbh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,26 +489,13 @@ struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = {


// log a function entry point
#ifndef _WIN32
#define PDO_LOG_DBH_ENTRY \
{ \
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( dbh->driver_data ); \
driver_dbh->set_func( __FUNCTION__ ); \
int length = strlen( __FUNCTION__ ) + strlen( ": entering" ); \
char func[length+1]; \
memset(func, '\0', length+1); \
strcpy_s( func, sizeof( __FUNCTION__ ), __FUNCTION__ ); \
strcat_s( func, length+1, ": entering" ); \
LOG( SEV_NOTICE, func ); \
if (driver_dbh != NULL) driver_dbh->set_func(__FUNCTION__); \
core_sqlsrv_register_severity_checker(pdo_severity_check); \
LOG(SEV_NOTICE, "%1!s!: entering", __FUNCTION__); \
}
#else
#define PDO_LOG_DBH_ENTRY \
{ \
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( dbh->driver_data ); \
driver_dbh->set_func( __FUNCTION__ ); \
LOG( SEV_NOTICE, __FUNCTION__ ## ": entering" ); \
}
#endif

// constructor for the internal object for connections
pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver TSRMLS_DC ) :
Expand Down Expand Up @@ -547,7 +534,7 @@ pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ vo
// 0 for failure, 1 for success.
int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_options TSRMLS_DC)
{
LOG( SEV_NOTICE, "pdo_sqlsrv_db_handle_factory: entering" );
PDO_LOG_DBH_ENTRY;

hash_auto_ptr pdo_conn_options_ht;
pdo_error_mode prev_err_mode = dbh->error_mode;
Expand Down
16 changes: 8 additions & 8 deletions source/pdo_sqlsrv/pdo_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv)
ZEND_TSRMLS_CACHE_UPDATE();
#endif

core_sqlsrv_register_logger( pdo_sqlsrv_log );
core_sqlsrv_register_severity_checker(pdo_severity_check);

REGISTER_INI_ENTRIES();

LOG( SEV_NOTICE, "pdo_sqlsrv: entering minit" );
PDO_LOG_NOTICE("pdo_sqlsrv: entering minit");

// initialize list of pdo errors
g_pdo_errors_ht = reinterpret_cast<HashTable*>( pemalloc( sizeof( HashTable ), 1 ));
Expand Down Expand Up @@ -200,7 +200,7 @@ PHP_MSHUTDOWN_FUNCTION(pdo_sqlsrv)
}
catch( ... ) {

LOG( SEV_NOTICE, "Unknown exception caught in PHP_MSHUTDOWN_FUNCTION(pdo_sqlsrv)" );
PDO_LOG_NOTICE("Unknown exception caught in PHP_MSHUTDOWN_FUNCTION(pdo_sqlsrv)");
return FAILURE;
}

Expand All @@ -225,18 +225,18 @@ PHP_RINIT_FUNCTION(pdo_sqlsrv)
int set_locale = PDO_SQLSRV_G(set_locale_info);
if (set_locale == 2) {
setlocale(LC_ALL, "");
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale LC_ALL");
PDO_LOG_NOTICE("pdo_sqlsrv: setlocale LC_ALL");
}
else if (set_locale == 1) {
setlocale(LC_CTYPE, "");
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale LC_CTYPE");
PDO_LOG_NOTICE("pdo_sqlsrv: setlocale LC_CTYPE");
}
else {
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale NONE");
PDO_LOG_NOTICE("pdo_sqlsrv: setlocale NONE");
}
#endif

LOG( SEV_NOTICE, "pdo_sqlsrv: entering rinit" );
PDO_LOG_NOTICE("pdo_sqlsrv: entering rinit");

return SUCCESS;
}
Expand All @@ -250,7 +250,7 @@ PHP_RSHUTDOWN_FUNCTION(pdo_sqlsrv)
SQLSRV_UNUSED( module_number );
SQLSRV_UNUSED( type );

LOG( SEV_NOTICE, "pdo_sqlsrv: entering rshutdown" );
PDO_LOG_NOTICE("pdo_sqlsrv: entering rshutdown");

return SUCCESS;
}
Expand Down
19 changes: 3 additions & 16 deletions source/pdo_sqlsrv/pdo_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,26 +351,13 @@ void stmt_option_fetch_datetime:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_op
}

// log a function entry point
#ifndef _WIN32
#define PDO_LOG_STMT_ENTRY \
{ \
pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast<pdo_sqlsrv_stmt*>( stmt->driver_data ); \
driver_stmt->set_func( __FUNCTION__ ); \
int length = strlen( __FUNCTION__ ) + strlen( ": entering" ); \
char func[length+1]; \
memset(func, '\0', length+1); \
strcpy_s( func, sizeof( __FUNCTION__ ), __FUNCTION__ ); \
strcat_s( func, length+1, ": entering" ); \
LOG( SEV_NOTICE, func ); \
if (driver_stmt != NULL) driver_stmt->set_func( __FUNCTION__ ); \
core_sqlsrv_register_severity_checker(pdo_severity_check); \
LOG(SEV_NOTICE, "%1!s!: entering", __FUNCTION__); \
}
#else
#define PDO_LOG_STMT_ENTRY \
{ \
pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast<pdo_sqlsrv_stmt*>( stmt->driver_data ); \
driver_stmt->set_func( __FUNCTION__ ); \
LOG( SEV_NOTICE, __FUNCTION__ ## ": entering" ); \
}
#endif

// PDO SQLSRV statement destructor
pdo_sqlsrv_stmt::~pdo_sqlsrv_stmt( void )
Expand Down
25 changes: 3 additions & 22 deletions source/pdo_sqlsrv/pdo_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ const int MAX_DIGITS = 11; // +-2 billion = 10 digits + 1 for the sign if negati
// the warning message is not the error message alone; it must take WARNING_TEMPLATE above into consideration without the formats
const int WARNING_MIN_LENGTH = static_cast<const int>( strlen( WARNING_TEMPLATE ) - strlen( "%1!s!%2!d!%3!s!" ));

// buffer used to hold a formatted log message prior to actually logging it.
const int LOG_MSG_SIZE = 2048;
char log_msg[LOG_MSG_SIZE] = {'\0'};

// internal error that says that FormatMessage failed
SQLCHAR INTERNAL_FORMAT_ERROR[] = "An internal error occurred. FormatMessage failed writing an error message.";

// Returns a sqlsrv_error for a given error code.
sqlsrv_error_const* get_error_message( _In_opt_ unsigned int sqlsrv_error_code);

Expand Down Expand Up @@ -623,22 +616,10 @@ void pdo_sqlsrv_retrieve_context_error( _In_ sqlsrv_error const* last_error, _Ou
}
}

// Formats the error message and writes to the php error log.
void pdo_sqlsrv_log( _In_opt_ unsigned int severity TSRMLS_DC, _In_opt_ const char* msg, _In_opt_ va_list* print_args )
// check the global variable of pdo_sqlsrv severity whether the message qualifies to be logged with the LOG macro
bool pdo_severity_check(_In_ unsigned int severity TSRMLS_DC)
{
if( (severity & PDO_SQLSRV_G( log_severity )) == 0 ) {
return;
}

DWORD rc = FormatMessage( FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, log_msg, LOG_MSG_SIZE, print_args );

// if an error occurs for FormatMessage, we just output an internal error occurred.
if( rc == 0 ) {
SQLSRV_STATIC_ASSERT( sizeof( INTERNAL_FORMAT_ERROR ) < sizeof( log_msg ));
std::copy( INTERNAL_FORMAT_ERROR, INTERNAL_FORMAT_ERROR + sizeof( INTERNAL_FORMAT_ERROR ), log_msg );
}

php_log_err( log_msg TSRMLS_CC );
return ((severity & PDO_SQLSRV_G(pdo_log_severity)));
}

namespace {
Expand Down
2 changes: 1 addition & 1 deletion source/pdo_sqlsrv/php_pdo_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
// request level variables
ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlsrv)

unsigned int log_severity;
unsigned int pdo_log_severity;
zend_long client_buffer_max_size;

#ifndef _WIN32
Expand Down
10 changes: 7 additions & 3 deletions source/pdo_sqlsrv/php_pdo_sqlsrv_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ extern HMODULE g_sqlsrv_hmodule;
#endif

PHP_INI_BEGIN()
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_LOG , "0", PHP_INI_ALL, OnUpdateLong, log_severity,
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_LOG , "0", PHP_INI_ALL, OnUpdateLong, pdo_log_severity,
zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals )
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE , INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong,
client_buffer_max_size, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals )
Expand Down Expand Up @@ -326,6 +326,10 @@ inline void pdo_reset_dbh_error( _Inout_ pdo_dbh_t* dbh TSRMLS_DC )
}
}

#define PDO_LOG_NOTICE(message) \
core_sqlsrv_register_severity_checker(pdo_severity_check); \
LOG(SEV_NOTICE, message);

#define PDO_RESET_DBH_ERROR pdo_reset_dbh_error( dbh TSRMLS_CC );

inline void pdo_reset_stmt_error( _Inout_ pdo_stmt_t* stmt )
Expand Down Expand Up @@ -417,8 +421,8 @@ namespace pdo {

} // namespace pdo

// logger for pdo_sqlsrv called by the core layer when it wants to log something with the LOG macro
void pdo_sqlsrv_log( _In_opt_ unsigned int severity TSRMLS_DC, _In_opt_ const char* msg, _In_opt_ va_list* print_args );
// check the global variable of pdo_sqlsrv severity whether the message qualifies to be logged with the LOG macro
bool pdo_severity_check(_In_ unsigned int severity TSRMLS_DC);


#endif /* PHP_PDO_SQLSRV_INT_H */
10 changes: 4 additions & 6 deletions source/shared/core_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,12 @@ struct sqlsrv_static_assert<true> { _In_ static const int value = 1; };
// Logging
//*********************************************************************************************************************************
// log_callback
// a driver specific callback for logging messages
// a driver specific callback for checking if the messages are qualified to be logged:
// severity - severity of the message: notice, warning, or error
// msg - the message to log in a FormatMessage style formatting
// print_args - args to the message
typedef void (*log_callback)( _In_ unsigned int severity TSRMLS_DC, _In_ const char* msg, _In_opt_ va_list* print_args );
typedef bool (*severity_callback)(_In_ unsigned int severity TSRMLS_DC);

// each driver must register a log callback. This should be the first thing a driver does.
void core_sqlsrv_register_logger( _In_ log_callback );
// each driver must register a severity checker callback for logging to work according to the INI settings
void core_sqlsrv_register_severity_checker(_In_ severity_callback driver_checker);

// a simple wrapper around a PHP error logging function.
void write_to_log( _In_ unsigned int severity TSRMLS_DC, _In_ const char* msg, ... );
Expand Down
39 changes: 33 additions & 6 deletions source/shared/core_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@

namespace {

severity_callback g_driver_severity;

// *** internal constants ***
log_callback g_driver_log;

// buffer used to hold a formatted log message prior to actually logging it.
const int LOG_MSG_SIZE = 2048;

// internal error that says that FormatMessage failed
SQLCHAR INTERNAL_FORMAT_ERROR[] = "An internal error occurred. FormatMessage failed writing an error message.";

// buffer used to hold a formatted log message prior to actually logging it.
char last_err_msg[2048] = {'\0'}; // 2k to hold the error messages

Expand All @@ -35,6 +41,25 @@ unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encodin
_In_ unsigned int mbcs_len,
_Out_writes_(utf16_len) __transfer( mbcs_in_string ) SQLWCHAR* utf16_out_string,
_In_ unsigned int utf16_len, bool use_strict_conversion = false );

// invoked by write_to_log() when the message severity qualifies to be logged
// msg - the message to log in a FormatMessage style formatting
// print_args - args to the message
void log_activity(_In_opt_ const char* msg, _In_opt_ va_list* print_args)
{
char log_msg[LOG_MSG_SIZE] = { '\0' };

DWORD rc = FormatMessage(FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, log_msg, LOG_MSG_SIZE, print_args);

// if an error occurs for FormatMessage, we just output an internal error occurred.
if (rc == 0) {
SQLSRV_STATIC_ASSERT(sizeof(INTERNAL_FORMAT_ERROR) < sizeof(log_msg));
std::copy(INTERNAL_FORMAT_ERROR, INTERNAL_FORMAT_ERROR + sizeof(INTERNAL_FORMAT_ERROR), log_msg);
}

php_log_err(log_msg TSRMLS_CC);
}

}

// SQLSTATE for all internal errors
Expand All @@ -47,22 +72,24 @@ SQLCHAR SSPWARN[] = "01SSP";
// the script (sqlsrv_configure).
void write_to_log( _In_ unsigned int severity TSRMLS_DC, _In_ const char* msg, ...)
{
SQLSRV_ASSERT( !(g_driver_log == NULL), "Must register a driver log function." );
SQLSRV_ASSERT( !(g_driver_severity == NULL), "Must register a driver checker function." );
if (!g_driver_severity(severity TSRMLS_CC)) {
return;
}

va_list args;
va_start( args, msg );

g_driver_log( severity TSRMLS_CC, msg, &args );
log_activity(msg, &args);

va_end( args );
}

void core_sqlsrv_register_logger( _In_ log_callback driver_logger )
void core_sqlsrv_register_severity_checker(_In_ severity_callback driver_checker)
{
g_driver_log = driver_logger;
g_driver_severity = driver_checker;
}


// convert a string from utf-16 to the encoding and return the new string in the pointer parameter and new
// length in the len parameter. If no errors occurred during convertion, true is returned and the original
// utf-16 string is released by this function if no errors occurred. Otherwise the parameters are not changed
Expand Down
15 changes: 8 additions & 7 deletions source/sqlsrv/conn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -629,10 +629,9 @@ const connection_option SS_CONN_OPTS[] = {

PHP_FUNCTION ( sqlsrv_connect )
{

LOG_FUNCTION( "sqlsrv_connect" );
SET_FUNCTION_NAME( *g_ss_henv_cp );
SET_FUNCTION_NAME( *g_ss_henv_ncp );
g_ss_henv_cp->set_func(_FN_);
g_ss_henv_ncp->set_func(_FN_);

reset_errors( TSRMLS_C );

Expand Down Expand Up @@ -785,7 +784,7 @@ PHP_FUNCTION( sqlsrv_close )

// dummy context to pass to the error handler
error_ctx = new (sqlsrv_malloc( sizeof( sqlsrv_context ))) sqlsrv_context( 0, ss_error_handler, NULL );
SET_FUNCTION_NAME( *error_ctx );
error_ctx->set_func(_FN_);

if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &conn_r) == FAILURE ) {

Expand Down Expand Up @@ -816,7 +815,7 @@ PHP_FUNCTION( sqlsrv_close )
throw ss::SSException();
}

SET_FUNCTION_NAME( *conn );
conn->set_func(_FN_);

// cause any variables still holding a reference to this to be invalid so they cause
// an error when passed to a sqlsrv function. There's nothing we can do if the
Expand Down Expand Up @@ -845,13 +844,15 @@ PHP_FUNCTION( sqlsrv_close )

void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC )
{
LOG_FUNCTION( "sqlsrv_conn_dtor" );
// Without sqlsrv_close(), this function is invoked by php during the final clean up stage.
// To prevent memory/resource leaks, no more logging at this point.
//LOG_FUNCTION( "sqlsrv_conn_dtor" );

// get the structure
ss_sqlsrv_conn *conn = static_cast<ss_sqlsrv_conn*>( rsrc->ptr );
SQLSRV_ASSERT( conn != NULL, "sqlsrv_conn_dtor: connection was null");

SET_FUNCTION_NAME( *conn );
conn->set_func(__func__);

// close all statements associated with the connection.
sqlsrv_conn_close_stmts( conn TSRMLS_CC );
Expand Down
4 changes: 2 additions & 2 deletions source/sqlsrv/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ PHP_MINIT_FUNCTION(sqlsrv)
{
SQLSRV_UNUSED( type );

core_sqlsrv_register_logger( ss_sqlsrv_log );
core_sqlsrv_register_severity_checker(ss_severity_check);

// our global variables are initialized in the RINIT function
#if defined(ZTS)
if( ts_allocate_id( &sqlsrv_globals_id,
Expand Down
12 changes: 4 additions & 8 deletions source/sqlsrv/php_sqlsrv_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,15 +313,11 @@ class sqlsrv_context_auto_ptr : public sqlsrv_auto_ptr< sqlsrv_context, sqlsrv_c
#define LOG_FUNCTION( function_name ) \
const char* _FN_ = function_name; \
SQLSRV_G( current_subsystem ) = current_log_subsystem; \
LOG( SEV_NOTICE, "%1!s!: entering", _FN_ );
core_sqlsrv_register_severity_checker(ss_severity_check); \
LOG(SEV_NOTICE, "%1!s!: entering", _FN_);

#define SET_FUNCTION_NAME( context ) \
{ \
(context).set_func( _FN_ ); \
}

// logger for ss_sqlsrv called by the core layer when it wants to log something with the LOG macro
void ss_sqlsrv_log( _In_ unsigned int severity TSRMLS_DC, _In_opt_ const char* msg, _In_opt_ va_list* print_args );
// check the global variables of sqlsrv severity whether the message qualifies to be logged with the LOG macro
bool ss_severity_check(_In_ unsigned int severity TSRMLS_DC);

// subsystems that may report log messages. These may be used to filter which systems write to the log to prevent noise.
enum logging_subsystems {
Expand Down
Loading

0 comments on commit 7214e8d

Please sign in to comment.