The following example program, monitor.c, demonstrates the steps outlined in the previous section. Commentary for each step follows the example.
/*monitor.c ** Example program showing logic flow of Monitor Client Library ** application. This example assumes the use of an ANSI C ** compliant compiler. This program creates two connections ** to the Monitor Server. Data is extracted from one connection ** at the beginning and end of the monitoring session. ** Data is extracted from the other connection every ** SAMPLE_INTERVAL seconds NUM_OF_SAMPLES times. */
#include <stdio.h> #include <stdlib.h> #include <ctype.h>
/* The mcpublic.h header file contains function prototypes, etc. ** for monitor client library functions. It also includes a ** header file called mctypes.h, which defines the datatypes ** used for monitor client library applications. */
#include "mcpublic.h"
#define NUM_OF_SAMPLES 10 #define SAMPLE_INTERVAL 5 #define NUM_SERVER_DATA_ITEMS 3 #define NUM_DB_INFO_ITEMS 14 #define NUM_NW_INFO_ITEMS 6 #define OPTIONAL_CALLS -1
/*Error signals*/ #define VIEW_NONEXISTENT -1 #define CONNECT_NONEXISTENT -1
SMC_RETURN_CODE main (SMC_INT argc, SMC_CHARP argv[]) {
SMC_VALUE_UNION serverNameUnion; SMC_VALUE_UNION userNameUnion; SMC_VALUE_UNION passwordUnion; SMC_VALUE_UNION interfacesFileUnion; SMC_VALUE_UNION workUnion; SMC_VALUE_UNION returnedDataUnion; SMC_CONNECT_ID connect1_id; SMC_CONNECT_ID connect2_id; SMC_VIEW_ID server_view_id; SMC_VIEW_ID db_info_view_id; SMC_VIEW_ID nw_info_view_id;
SMC_RETURN_CODE ret; SMC_DATAITEM_TYPE dataitem_type; /*Holds data item type returned by get_dataitem_type function call*/
/*Needed if alarms and filters are used */ #ifdef OPTIONAL_CALLS SMC_ALARM_ID alarm_id; SMC_FILTER_ID filter_id; SMC_CHARP filter_strings[2]; /*datatype is pointer to string. This is an array of pointers.*/ #endif SMC_SIZET row,num_of_rows,item; /*This is an integer data type*/ SMC_SIZET outputLength; /*Length of output returned by smc_connect_props function call*/
/* ** Definition of SMC_DATAITEM_STRUCT datatype */ SMC_DATAITEM_STRUCT server_info_view[NUM_SERVER_DATA_ITEMS]; SMC_DATAITEM_STRUCT db_info_view[NUM_DB_INFO_ITEMS]; SMC_DATAITEM_STRUCT nw_bytes_view[NUM_NW_INFO_ITEMS]; SMC_VALUE_UNION server_data[NUM_SERVER_DATA_ITEMS]; SMC_VALUE_UNION db_data[NUM_DB_INFO_ITEMS]; SMC_VALUE_UNION nw_data[NUM_NW_INFO_ITEMS];
/*Callback function prototypes. Actual functions are defined ** below. */ SMC_VOID errorCallback(SMC_CONNECT_ID,SMC_COMMAND_ID,SMC_VOIDP); SMC_VOID alarmCallback(SMC_CONNECT_ID,SMC_COMMAND_ID,SMC_VOIDP); SMC_BOOL explicitInterfacesFile = FALSE; int index,iterations;
/* ** These are labels used when printing out data returned by the ** database info view. */ SMC_CHARP db_info_labels[NUM_DB_INFO_ITEMS] = { "Database ID: ", "Object ID: ", "Database name: ", "Object name: ", "Page hit percent: ", "Page I/O: ", "Page logical reads this sample: ", "Page logical reads this session: ", "Page logical read rate this sample: ", "Page logical read rate this session: ", "Page physical reads this sample: ", "Page physical reads this session: ", "Page physical read rate this sample: ", "Page physical read rate this session: " };
/* ** These are labels used when printing out data returned by ** network info view. */ SMC_CHARP nw_info_labels[NUM_NW_INFO_ITEMS] = { "Network bytes received this sample: ", "Network bytes received this session: ", "Network bytes sent this sample: ", "Network bytes sent this session: ", "Network byte I/O rate this sample: ", "Network byte I/O rate this session: " }; if (argc <5){ printf("Usage <%s> -U <user_name> [-P <password>]\ -S <monserver name> [-I <interfaces_file>]\n",argv[0]); exit(1); }
/*
** Connect to a server.
*/
For commentary, see “Step 2: connect to a server”
/*
** Allocate first connection
*/ ret=smc_connect_alloc(errorCallback, &connect1_id /*Pointer to connect_id!*/ ); if (ret != SMC_RET_SUCCESS) { printf("Attempt to allocate first connection failed \ with error %d.\n",ret); exit(1); }
/* ** Allocate second connection */ ret=smc_connect_alloc(errorCallback, &connect2_id /*Pointer to connect_id!*/ ); if (ret != SMC_RET_SUCCESS) { printf("Attempt to allocate second connection failed \ with error %d.\n",ret); exit(1); }
/*
** Set mandatory and some optional connection properties.
** Mandatory connection properties are user name, server name, ** and password if user password is not NULL. If interfaces ** file name is not set, default is "interfaces" in directory ** pointed to by $SYBASE environment variable.
For commentary, see “Required connection properties”.
*/
for (index=1;index<argc;index++) {
/*User name*/
if (strncmp(argv[index],"-U",2) == 0) { userNameUnion.stringValue = argv[index+1]; ret=smc_connect_props(connect1_id, SMC_PROP_ACT_SET, /*Property action*/ SMC_PROP_USERNAME,/*Property*/ &userNameUnion, /*Note that union, not member of union, is used for property value*/ SMC_NULLTERM, /*Indicates null- terminated string for buffer length*/ NULL /*Use NULL when setting a property*/ ); } /*End if argument is user name*/ if (ret != SMC_RET_SUCCESS) { printf("Could not set user name.\n"); exit(SMC_RET_FAILURE); } /*Password. Default password is a null string*/
if (strncmp(argv[index],"-P",2) == 0) { passwordUnion.stringValue = argv[index+1]; ret=smc_connect_props(connect1_id, SMC_PROP_ACT_SET, /*Property action*/ SMC_PROP_PASSWORD,/*Property*/ &passwordUnion, /*Note that union, not member of union, is used for property value*/ SMC_NULLTERM, /*Indicates null- terminated string for buffer length*/ NULL /*Use NULL when setting a property*/ ); } /*End if argument is password*/ if (ret != SMC_RET_SUCCESS) { printf("Could not set password.\n"); exit(SMC_RET_FAILURE); }
/*Server name*/ if (strncmp(argv[index],"-S",2) == 0) { serverNameUnion.stringValue = argv[index+1]; ret=smc_connect_props(connect1_id, SMC_PROP_ACT_SET, /*Property action*/ SMC_PROP_SERVERNAME,/*Property*/ &serverNameUnion, /*Note that union, not member of union, is used for property value*/ SMC_NULLTERM, /*Indicates null- terminated string for buffer length*/ NULL /*Use NULL when setting a property*/ ); } /*End if argument is server name*/ if (ret != SMC_RET_SUCCESS) { printf("Could not set server name.\n"); exit(SMC_RET_FAILURE); } /*Interfaces file. If unspecified, $SYBASE/interfaces is used*/ if (strncmp(argv[index],"-I",2) == 0) { interfacesFileUnion.stringValue = argv[index+1]; ret=smc_connect_props(connect1_id, SMC_PROP_ACT_SET, /*Property action*/ SMC_PROP_IFILE, /*Property*/ &interfacesFileUnion, /*Note that pointer to union, not member of union,is used for property value*/ SMC_NULLTERM, /*Indicates null- terminated string for buffer length*/ NULL /*Use NULL when setting a property*/ ); explicitInterfacesFile = TRUE; } /*End if argument is interfaces file pathname*/ if (ret != SMC_RET_SUCCESS) { printf("Could not set interfaces file name.\n"); printf("Using default interfaces file.\n"); } } /*End for loop getting connection properties from command-line arguments*/
/* ** Optional smc_get_connect_props call that sets a pointer to be ** passed to error callback. In this case, the pointer is to a ** string that tells which connection encountered the error. */ workUnion.voidpValue = "first connection"; /*Call to set user data handle looks for value to set in void pointer member of union.*/ ret=smc_connect_props(connect1_id,SMC_PROP_ACT_SET,\ SMC_PROP_USERDATA,&workUnion,SMC_NULLTERM,NULL); if (ret != SMC_RET_SUCCESS){ printf("smc_connect_props call failed to \ set userDataHandle.\n"); }
/* ** Demonstration of "get" mode for smc_get_connect_props */ /*Check if user name has been set*/ ret=smc_connect_props(connect1_id, SMC_PROP_ACT_GET,/*Property action is "get"*/ SMC_PROP_USERNAME, &workUnion, SMC_UNUSED, /*Length parameter ignored on "get" operations*/ &outputLength /*Note this is a pointer!*/ ); if (ret != SMC_RET_SUCCESS) { printf ("Could not get user name. Execution continuing.\n"); } else { if (outputLength == 0) { printf("User name not set. Quitting execution.\n"); exit(SMC_RET_FAILURE); } else {
/* ** Application is responsible for freeing ** memory allocated to string member of SMC_VALUE_UNION by ** library. */
free(workUnion.stringValue); } } /*Check if server name has been set*/
ret=smc_connect_props(connect1_id, SMC_PROP_ACT_GET,/*Property action is "get"*/ SMC_PROP_SERVERNAME, &workUnion, SMC_UNUSED, /*Length parameter ignored on "get" operations*/ &outputLength /*Note this is a pointer!*/ ); if (ret != SMC_RET_SUCCESS) { printf ("Could not get server name. Execution continuing.\n"); } else { if (outputLength == 0) { printf("Server name not set. Quitting execution.\n");
exit(SMC_RET_FAILURE); } else { free(workUnion.stringValue); } }
/* ** Allocate properties for second connection. No need to ** repeat error checking. */
ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \ SMC_PROP_USERNAME,&userNameUnion,SMC_NULLTERM, NULL); if (ret != SMC_RET_SUCCESS) { printf("Could not set user name for second connection.\n"); exit(SMC_RET_FAILURE); } ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \ SMC_PROP_PASSWORD,&passwordUnion,SMC_NULLTERM,NULL); if (ret != SMC_RET_SUCCESS) { printf("Could not set password for second connection.\n"); exit(SMC_RET_FAILURE); } ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \ SMC_PROP_SERVERNAME,&serverNameUnion,SMC_NULLTERM,NULL); if (ret != SMC_RET_SUCCESS) { printf("Could not set server name for second connection.\n"); exit(SMC_RET_FAILURE); } if (explicitInterfacesFile) { ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \ SMC_PROP_IFILE,&interfacesFileUnion,SMC_NULLTERM,NULL); if (ret != SMC_RET_SUCCESS) { printf("Could not set server name for second connection.\n"); exit(SMC_RET_FAILURE); } }
/* ** Optional smc_connect_props call to set user-defined pointer to ** be passed to error callback. This pointer points to a ** string that tells where the error callback was triggered. */ workUnion.voidpValue = "second connection"; /*Call to set user data handle looks for value to set in void pointer member of union.*/ ret=smc_connect_props(connect2_id,SMC_PROP_ACT_SET, \ SMC_PROP_USERDATA,&workUnion,SMC_NULLTERM,NULL); if (ret != SMC_RET_SUCCESS){ printf("smc_connect_props call failed to set userDataHandle.\n"); }
/*
** Connect to monitor server
For commentary, see “Connecting to a server”
*/ /* ** First connection */ ret=smc_connect_ex(connect1_id); if (ret != SMC_RET_SUCCESS) { printf("First connection failed to connect to \ monitor server.\n"); exit(SMC_RET_FAILURE); }
/* ** Second connection */ ret=smc_connect_ex(connect2_id); if (ret != SMC_RET_SUCCESS) { printf("Second connection failed to connect to \ monitor server.\n"); exit(SMC_RET_FAILURE); }
/* ** Create views on connections. */
For commentary, see “Step 3: create a view”
** Define views.
/*
** Each data item must be paired with a ** statistic type . View definitions are used in create_view ** calls after connecting to monitor server. */ /*This is a server-wide view that returns one row of data*/
server_info_view[0].dataItemName =SMC_NAME_SQL_SERVER_NAME; server_info_view[0].dataItemStatType = SMC_STAT_VALUE_SAMPLE; server_info_view[1].dataItemName = SMC_NAME_SQL_SERVER_VERSION; server_info_view[1].dataItemStatType = SMC_STAT_VALUE_SAMPLE; server_info_view[2].dataItemName = SMC_NAME_TIMESTAMP; server_info_view[2].dataItemStatType = SMC_STAT_VALUE_SAMPLE;
/* ** This is a view with key and result data items that returns ** multiple rows of data. */
db_info_view[0].dataItemName = SMC_NAME_DB_ID; /*Key data items*/ db_info_view[0].dataItemStatType = SMC_STAT_VALUE_SAMPLE; db_info_view[1].dataItemName = SMC_NAME_OBJ_ID; db_info_view[1].dataItemStatType = SMC_STAT_VALUE_SAMPLE; db_info_view[2].dataItemName = SMC_NAME_DB_NAME; /*Result data items*/ db_info_view[2].dataItemStatType = SMC_STAT_VALUE_SAMPLE; db_info_view[3].dataItemName = SMC_NAME_OBJ_NAME; db_info_view[3].dataItemStatType = SMC_STAT_VALUE_SAMPLE; db_info_view[4].dataItemName = SMC_NAME_PAGE_HIT_PCT; db_info_view[4].dataItemStatType = SMC_STAT_VALUE_SAMPLE; db_info_view[5].dataItemName =SMC_NAME_PAGE_IO; db_info_view[5].dataItemStatType = SMC_STAT_VALUE_SAMPLE; db_info_view[6].dataItemName = SMC_NAME_PAGE_LOGICAL_READ; db_info_view[6].dataItemStatType = SMC_STAT_VALUE_SAMPLE; db_info_view[7].dataItemName = SMC_NAME_PAGE_LOGICAL_READ; db_info_view[7].dataItemStatType = SMC_STAT_VALUE_SESSION; db_info_view[8].dataItemName = SMC_NAME_PAGE_LOGICAL_READ; db_info_view[8].dataItemStatType = SMC_STAT_RATE_SAMPLE; db_info_view[9].dataItemName = SMC_NAME_PAGE_LOGICAL_READ; db_info_view[9].dataItemStatType = SMC_STAT_RATE_SESSION; db_info_view[10].dataItemName = SMC_NAME_PAGE_PHYSICAL_READ; db_info_view[10].dataItemStatType = SMC_STAT_VALUE_SAMPLE; db_info_view[11].dataItemName = SMC_NAME_PAGE_PHYSICAL_READ; db_info_view[11].dataItemStatType = SMC_STAT_VALUE_SESSION; db_info_view[12].dataItemName = SMC_NAME_PAGE_PHYSICAL_READ; db_info_view[12].dataItemStatType = SMC_STAT_RATE_SAMPLE; db_info_view[13].dataItemName = SMC_NAME_PAGE_PHYSICAL_READ; db_info_view[13].dataItemStatType = SMC_STAT_RATE_SESSION;
/* ** Another server-wide view */ nw_bytes_view[0].dataItemName = SMC_NAME_NET_BYTES_RCVD; nw_bytes_view[0].dataItemStatType = SMC_STAT_VALUE_SAMPLE; nw_bytes_view[1].dataItemName = SMC_NAME_NET_BYTES_RCVD; nw_bytes_view[1].dataItemStatType = SMC_STAT_VALUE_SESSION; nw_bytes_view[2].dataItemName = SMC_NAME_NET_BYTES_SENT; nw_bytes_view[2].dataItemStatType = SMC_STAT_VALUE_SAMPLE; nw_bytes_view[3].dataItemName = SMC_NAME_NET_BYTES_SENT; nw_bytes_view[3].dataItemStatType = SMC_STAT_VALUE_SESSION; nw_bytes_view[4].dataItemName = SMC_NAME_NET_BYTE_IO; nw_bytes_view[4].dataItemStatType = SMC_STAT_RATE_SAMPLE; nw_bytes_view[5].dataItemName = SMC_NAME_NET_BYTE_IO; nw_bytes_view[5].dataItemStatType = SMC_STAT_RATE_SESSION;
ret=smc_create_view (connect1_id, /*Connect ID assigned when connect allocated*/ server_info_view, /*This is a pointer to array of SMC_DATAITEM_STRUCTS which defines the view*/ NUM_SERVER_DATA_ITEMS, /*No. of items in the view*/ "server info view", /*Ignored on a live connection*/ &server_view_id /*Value is assigned by this call*/ ); if (ret != SMC_RET_SUCCESS) { /*Cleanup from failed create_view call*/ ret=smc_connect_drop(connect1_id); /*Create view failed so no further use for this connection*/ connect1_id = CONNECT_NONEXISTENT; } /* ** The second connection will have two views */ ret=smc_create_view(connect2_id,db_info_view,NUM_DB_INFO_ITEMS, "db info view",&db_info_view_id); if (ret != SMC_RET_SUCCESS) { db_info_view_id = VIEW_NONEXISTENT; } ret=smc_create_view(connect2_id,nw_bytes_view,NUM_NW_INFO_ITEMS, "nw bytes view",&nw_info_view_id); if (ret != SMC_RET_SUCCESS) { nw_info_view_id = VIEW_NONEXISTENT; }
/*
** Create a filter.
*/
For commentary, see “Step 4: create filters”
/* ** Filters and alarms may be applied to data items within a view. ** This is optional. ** In this case, we only want to see I/O activity for a ** particular database and tempdb. If any physical reads occur, ** an alarm is triggered that posts a message to the screen. */
#ifdef OPTIONAL_CALLS filter_strings[0] = "my_db"; /*Change to db of interest*/ filter_strings[1] = "tempdb"; workUnion.voidpValue = filter_strings; ret=smc_create_filter(connect2_id, /*Connection id*/ db_info_view_id, /*View id*/ &db_info_view[2], /*Pointer to a data item within the view to be filtered*/ SMC_FILT_T_EQ, /*Type of filter*/ &workUnion, /*Filter value*/ 2, /*Number of elements in array of filter values*/ SMC_DI_TYPE_CHARP, /*datatype of filter values*/ &filter_id /*Value is assigned by this function call*/ ); if (ret != SMC_RET_SUCCESS) { printf("Filters were not applied. Continuing execution.\n"); }
/*
** Set alarms.
*/
For commentary, see “Step 5: set alarms”
workUnion.longValue = 1; /*Value above which alarm is triggered*/ ret=smc_create_alarm_ex(connect2_id, /*Connection id*/ db_info_view_id, /*View id*/ &db_info_view[11], /*Pointer to a data item within the view to which the alarm is applied*/ &workUnion, /*Where value that triggers the alarm is located*/ SMC_DI_TYPE_LONG, /*datatype of item to which alarm is applied*/ SMC_ALARM_A_NOTIFY,/*Trigger alarm callback function. This is the only action possible when the server mode is LIVE.*/ NULL, /*For server mode HISTORICAL, this is where log file to be written to or program to be run is specified. For server mode LIVE, this field is ignored.*/
/*The following is a string that is passed to the alarm callback function.*/
"Physical read occurred in database.", alarmCallback, /*Alarm callback function*/ &alarm_id /*Variable into which alarm id is placed.*/ ); if (ret != SMC_RET_SUCCESS) { printf("Alarm was not applied. Execution continuing.\n"); } #endif
/*
** Request data and process results.
*/
For commentary, see “Step 6: request performance data and process results”
/* ** Get data from first connection. As server name and version ** do not change during the connection, we only get it once. ** Post the time when the refresh was done. */ if (connect1_id != CONNECT_NONEXISTENT) { /*If the connect is not successful,the error callback is triggered. For a friendlier display, we check first.*/ ret=smc_refresh_ex(connect1_id, /*ID of connect*/ 0 /*STEP not used in live connection*/ ); if (ret != SMC_RET_SUCCESS) { printf("refresh call failed on first connect ID.\n"); } else { /*Check row count even though only one row is expected in this case. If no rows are returned, get_dataitem_value calls will return errors.*/ ret=smc_get_row_count(connect1_id, server_view_id, #_of_rows); if (ret != SMC_RET_SUCCESS){ printf("Get row count call failed.\n"); } else { if (num_of_rows > 0){
/* ** A get_dataitem_value call is made for each item in the view. ** The retrieved data is stored in an array of SMC_VALUE_UNIONs. */ for (index=0;index <NUM_SERVER_DATA_ITEMS;index++){ ret=smc_get_dataitem_value(connect1_id, server_view_id, &server_info_view[index],/*Look at each data item in the view*/ 0, /*Only one row of data is returned for this particular view, so the value for row is hard-coded in this case.*/ &server_data[index] /*Retrieved data stored here*/ ); } /*End for loop*/
/* ** Display the returned data. */
printf("Adaptive Server Enterprise name is: \ %s.\n",server_data[0].stringValue); printf("Adaptive Server Enterprise version is: \ %s.\n",server_data[1].stringValue); printf("Date and time is: \ %s.\n",server_data[2].stringValue);
/* ** The application is responsible for freeing memory allocated ** by the Monitor Client Library for string members of ** SMC_VALUE_UNIONs. This also illustrates the use of the ** smc_get_dataitem_type function call. */ for (index=0;index <NUM_SERVER_DATA_ITEMS;index++){ ret=smc_get_dataitem_type(&server_info_view[index], \ &dataitem_type); if (ret != SMC_RET_SUCCESS) { printf("Get dataitem type failed for item %d \ in server_info_view.\n"); } else { if (dataitem_type == SMC_DI_TYPE_CHARP) { free(server_data[index].stringValue); } } } /*End for loop*/ } /*End if number of rows > 0*/ } /*End case get_row_count was successful*/ } /*End case smc_refresh_ex call was successful*/ } /*End case connect still valid*/ /* ** Get the data from the views in the second connection to see ** how the data changes over time. To do this, we sample ** NUM_OF_SAMPLES times, pausing SAMPLE_INTERVAL times between ** each sample. The process of retrieving data is within a loop. */
for (iterations=0;iterations<NUM_OF_SAMPLES;iterations++){ sleep(SAMPLE_INTERVAL); ret=smc_refresh_ex(connect2_id, /*Note second connection specified for refresh*/ 0 /*Step not used in live connection*/ ); if (ret == SMC_RET_SUCCESS) { if (db_info_view_id != VIEW_NONEXISTENT){ /*Attempting get_row_count for nonexistent view will cause errors so check if view was actually created*/ ret=smc_get_row_count(connect2_id, db_info_view_id, #_of_rows /*Multiple rows will be returned. For each row of data returned, use get_dataitem_value loop. Function call puts number of rows returned into variable.*/ ); for(row=0;row<num_of_rows;row++){ for (index=0;index <NUM_DB_INFO_ITEMS;index++){ ret=smc_get_dataitem_value(connect2_id, db_info_view_id, /*View specified for get_dataitem_value.*/ &db_info_view[index], row, /*Multiple rows in this case */ &db_data[index] ); if (ret != SMC_RET_SUCCESS) { printf("Get dataitem value failed for data item \ %s.\n",db_info_labels[index]); } else { printf("%s",db_info_labels[index]); ret=smc_get_dataitem_type(&db_info_view[index],\ &dataitem_type); if (ret != SMC_RET_SUCCESS){ printf("Get data item type failed for data item \ %s.\n",db_info_view[index]); } else { switch (dataitem_type) { case SMC_DI_TYPE_CHARP: printf("%s.\n",db_data[index].stringValue); free(db_data[index].stringValue); /*Application is responsible for freeing memory allocated for strings by library*/ break; case SMC_DI_TYPE_LONG: printf("%d.\n",db_data[index].longValue); break; case SMC_DI_TYPE_DOUBLE: /*Rates are generally floating point variables*/ printf("%f.\n",db_data[index].doubleValue); break; default: printf("Unknown datatype encountered.\n"); break; } /*End switch*/ } /*End case get_dataitem_type successful*/ } /*End case get_dataitem_value successful*/ } /*End for loop to get each data item value*/ } /*End for loop to get each row of data*/ } /*End case view exists*/
/* ** Retrieve data from second view in refresh. ** Processing is much the same. */ if (nw_info_view_id != VIEW_NONEXISTENT){ /*Attempting get_row_count for nonexistent view causes errors, so check to see if view was actually created*/ ret=smc_get_row_count(connect2_id, nw_info_view_id, #_of_rows /*This is a server- wide view so only one row should be returned*/ ); if (num_of_rows > 0 ){ for (index=0;index <NUM_NW_INFO_ITEMS;index++){ ret=smc_get_dataitem_value(connect2_id, nw_info_view_id, /*Note view specified for get_dataitem_value*/ &nw_bytes_view[index], 0, /*One row in this case*/ &nw_data[index] ); if (ret != SMC_RET_SUCCESS) { printf("Get dataitem value failed for data item \ %s.\n",nw_info_labels[index]); } else { printf("%s",nw_info_labels[index]); ret=smc_get_dataitem_type(&nw_bytes_view[index],\ &dataitem_type); if (ret != SMC_RET_SUCCESS){ printf("Get data item type failed for data item \ %s.\n",nw_bytes_view[index]); } else { switch (dataitem_type) { case SMC_DI_TYPE_CHARP: printf("%s.\n",nw_data[index].stringValue); free(nw_data[index].stringValue); /*Application is responsible for freeing memory allocated for strings by library*/ break; case SMC_DI_TYPE_LONG: printf("%d.\n",nw_data[index].longValue); break; case SMC_DI_TYPE_DOUBLE: /*Rates are generally floating point variables*/ printf("%f.\n",nw_data[index].doubleValue); break; default: printf("Unknown datatype encountered.\n"); break; } /*End switch*/ } /*End case get_dataitem_type successful*/ } /*End case get_dataitem_value successful*/ } /*End for loop to get each data item value*/ } /*End if any rows of data returned*/ else { printf("No data returned for network info view.\n"); } } /*End case view exists*/ } /*End case refresh successful*/ else { printf("Refresh of second connect failed. \ Return code is %d.\n",ret); } } /*End for loop for number of iterations*/
/* ** This shows how to drop filters and alarms. It is not necessary ** to do this prior to closing a connection, as it is done ** automatically when the connection is closed. Filters may be ** dropped, for example, to see the filtered results of a query ** followed by the unfiltered results. */ #ifdef OPTIONAL_CALLS ret=smc_drop_filter(connect2_id,db_info_view_id,filter_id); if (ret != SMC_RET_SUCCESS) { printf("Attempt to drop filter failed.\n"); } ret=smc_drop_alarm(connect2_id,db_info_view_id,alarm_id); if (ret != SMC_RET_SUCCESS) { printf("Attempt to drop alarm failed.\n"); } #endif
/* ** Get another time stamp before disconnecting. To do this, ** do a refresh on the first connection again and only display ** the time stamp data returned. */ if (connect1_id != CONNECT_NONEXISTENT) { ret=smc_refresh_ex(connect1_id,0 ); if (ret != SMC_RET_SUCCESS) { printf("refresh call failed on first connect ID.\n"); } else { /*Check row count even though only one row is expected. If no rows are returned, get_dataitem_value calls will return errors.*/ ret=smc_get_row_count(connect1_id, server_view_id, #_of_rows); if (ret != SMC_RET_SUCCESS){ printf("Get row count call on first connection \ failed.\n"); } else { if (num_of_rows > 0){ ret=smc_get_dataitem_value(connect1_id, server_view_id, &server_info_view[2], /*In this case we are only interested in the third data item*/ 0, /*Only one row of data is returned for this particular view, so the value for row is hard- coded in this case.*/ &server_data[2] ); printf("Date and time on conclusion of monitoring:\ %s\n",server_data[2].stringValue); free(server_data[2].stringValue); /*Application must free string memory returned by library*/ } /*End if row of data returned*/ } /*End case get_row_count successful*/ } /*End case refresh successful*/ } /*End case connection exists*/
/*
** Close and deallocate the connection.
*/
For commentary, see “Step 7: close and deallocate connections”
/* ** Cleanup. This consists of closing all connections, then ** de-allocating them. Alternatively, connections can be re-used. */ ret=smc_close(connect1_id, SMC_CLOSE_REQUEST /*Close only if no outstanding commands (only close request type currently supported)*/ ); if (ret != SMC_RET_SUCCESS) { printf("Attempt to close first connection failed. \ Return code is %d.\n",ret); } ret=smc_close(connect2_id,SMC_CLOSE_REQUEST); if (ret != SMC_RET_SUCCESS) { printf("Attempt to close second connection failed. \ Return code is %d.\n",ret); }
/* ** Connections can be re-used at this point, for example, to ** connect to different servers. However, we de-allocate them. */ ret=smc_connect_drop(connect1_id); if (ret != SMC_RET_SUCCESS){ printf("Attempt to drop first connection failed. \ Return code is %d.\n",ret); } ret=smc_connect_drop(connect2_id); if (ret != SMC_RET_SUCCESS){ printf("Attempt to drop second connection failed. \ Return code is %d.\n",ret); } return(SMC_RET_SUCCESS); } /*End main*/
/*
** Callback functions
For commentary, see “Step 1: define error handling”.
*/ SMC_VOID errorCallback( SMC_CONNECT_ID connectID, SMC_COMMAND_ID commandID, /*Value internal to Monitor Client Library*/ SMC_VOIDP userDataHandle /*User-defined pointer. Set by smc_connect_propscall*/ ) { SMC_SIZET ret; SMC_VALUE_UNION errorInfo; /*Used for getting information from smc_get_command_info function call*/ SMC_SIZET returned_msg_length; printf ("Inside new error callback.\n");
/* ** Use smc_get_command_info function call to get information ** from error and alarm callbacks. */ ret=smc_get_command_info(connectID, commandID, SMC_INFO_ERR_MAPSEVERITY, /*Information requested about command*/ &errorInfo, /*Where information returned about command is placed*/ NULL /*Value is numeric so length of returned data not needed*/
); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call requesting error map \ severity failed. Error returned is: %d\n",ret); } else{ printf("Monitor Client Library error severity level is: \ %d\n",errorInfo.sizetValue); } ret=smc_get_command_info(connectID, commandID, SMC_INFO_ERR_MSG, &errorInfo, &returned_msg_length /*Find string length */ ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call requesting error message \ failed. Error returned is: %d\n",ret); } else{ printf("Error message text is: %s\n",errorInfo.stringValue); free(errorInfo.stringValue); /*Application is responsible for freeing string buffer memory allocated by library*/ } ret=smc_get_command_info(connectID, commandID, SMC_INFO_ERR_NUM, &errorInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call requesting error number \ failed. Error returned is: %d\n",ret); } else{ printf("Error number is: %d\n",errorInfo.sizetValue);
} ret=smc_get_command_info(connectID, commandID, SMC_INFO_ERR_SEVERITY, &errorInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call requesting error severity \ failed. Error returned is: %d\n",ret); } else{ printf("Error severity level is: %d\n",errorInfo.sizetValue); } ret=smc_get_command_info(connectID, commandID, SMC_INFO_ERR_SOURCE, &errorInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call requesting error source \ failed. Error returned is: %d\n",ret); } else{ printf(" Error source is: %d\n",errorInfo.sizetValue); } ret=smc_get_command_info(connectID, commandID, SMC_INFO_ERR_STATE, &errorInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call requesting state failed. \ Error returned is: %d\n",ret); } else{ printf(" Error state is: %d\n",errorInfo.sizetValue); }
/* ** Demonstrate use of userDataHandle. This value was set as a ** connection property for the connection in the main program and ** is passed to this function. */ if (userDataHandle != NULL){ printf("Connection on which error occurred is \ %s.\n",userDataHandle); } } /*End errorCallback */ /*Alarm callback*/ SMC_VOID alarmCallback( SMC_CONNECT_ID connectID, SMC_COMMAND_ID commandID, /*Value internal to Monitor Client Library*/ SMC_VOIDP userDataHandle ) { #define MSG_BUFFER_LENGTH 80 SMC_SIZET ret; SMC_VALUE_UNION alarmInfo; /*Union into which requested data is placed*/ SMC_SIZET returned_msg_length; printf ("Alarm callback triggered.\n");
/* ** Use smc_get_command_info function call to get information ** from error and alarm callbacks. */ ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_ALARMID, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else{ printf("Alarm ID is: %d\n",alarmInfo.sizetValue); }
/* ** This demonstrates the use of the SMC_INFO_ALARM_VALUE_DATATYPE ** information that might be useful in a generic alarm callback ** function. */ ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_VALUE_DATATYPE, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else{ switch(alarmInfo.intValue){ case SMC_DI_TYPE_INT: ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_CURRENT_VALUE, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else { printf("Current value of alarmed data item is:\ %d.\n",alarmInfo.intValue); } break; case SMC_DI_TYPE_LONG: ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_CURRENT_VALUE, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else { printf("Current value of alarmed data item is: \ %d.\n",alarmInfo.longValue); } break; case SMC_DI_TYPE_DOUBLE: ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_CURRENT_VALUE, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. Error returned is: %d",ret); } else { printf("Current value of alarmed data item is: \ %f.\n",alarmInfo.doubleValue); } break; default: printf("Invalid value returned for datatype of \ current alarm value.\n"); break; } /*End switch*/ } ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_ROW, &alarmInfo, NULL );
if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else{ printf("Row of data which triggered alarm is: \ %d\n",alarmInfo.sizetValue); } ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_VALUE_DATATYPE, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else{ switch(alarmInfo.intValue){ case SMC_DI_TYPE_INT: ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_THRESHOLD_VALUE, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else { printf("Value of data item exceeded alarm-triggering \ value of: %d.\n",alarmInfo.intValue); } break; case SMC_DI_TYPE_LONG: ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_THRESHOLD_VALUE, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else { printf("Value of data item exceeded alarm-triggering \ value of: %d.\n",alarmInfo.longValue); } break; case SMC_DI_TYPE_DOUBLE: ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_THRESHOLD_VALUE, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else { printf("Value of data item exceeded alarm-triggering\ value of: %f.\n",alarmInfo.doubleValue); } break; default: printf("Invalid value returned for datatype of \ THRESHOLD alarm value.\n"); break; } /*End switch*/ } ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_TIMESTAMP, &alarmInfo, &returned_msg_length ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else{ printf("Time when alarm was triggered is: \ %s\n",alarmInfo.stringValue); free(alarmInfo.stringValue); /*Application is responsible for freeing string buffer memory allocated by library.*/ } ret=smc_get_command_info(connectID, commandID, SMC_INFO_ALARM_VIEWID, &alarmInfo, NULL ); if (ret != SMC_RET_SUCCESS){ printf("get_command_info call failed. \ Error returned is: %d",ret); } else{ printf("ID of view which triggered alarm is: \ %d.\n",alarmInfo.sizetValue); } } /*End newAlarmCallback*/