C language logging and runtime information
This example uses the following file name:log.c
Code
The code in this example explores functionality that may not be commonly used. Logging can be used to help trace the execution of an AE. To be of use, the AE must be registered with a log mask and logging must be enabled via nzudxdbg. To receive system logging messages in the window where the NPS system was started, you need to start NPS with the '-i' option (for example, 'nzstart -i'). This causes the NPS processes to remain attached to the terminal. Runtime information provides statistics about the NPS system, including the number of dataslices, the number of SPUs, and locus of execution.
#include <stdio.h>
#include <stdlib.h>
#include "nzaeapis.h"
static int run(NZAE_HANDLE h);
int main(int argc, char * argv[])
{
if (nzaeIsLocal())
{
NzaeInitialization arg;
memset(&arg, 0, sizeof(arg));
arg.ldkVersion = NZAE_LDK_VERSION;
if (nzaeInitialize(&arg))
{
fprintf(stderr, "initialization failed\n");
return -1;
}
run(arg.handle);
nzaeClose(arg.handle);
}
else {
NZAECONPT_HANDLE hConpt = nzaeconptCreate();
if (!hConpt)
{
fprintf(stderr, "error creating connection point\n");
fflush(stderr);
return -1;
}
const char * conPtName = nzaeRemprotGetRemoteName();
if (!conPtName)
{
fprintf(stderr, "error getting connection point name\n");
fflush(stderr);
exit(-1);
}
if (nzaeconptSetName(hConpt, conPtName))
{
fprintf(stderr, "error setting connection point name\n");
fflush(stderr);
nzaeconptClose(hConpt);
return -1;
}
NzaeremprotInitialization args;
memset(&args, 0, sizeof(args));
args.ldkVersion = NZAE_LDK_VERSION;
args.hConpt = hConpt;
if (nzaeRemprotCreateListener(&args))
{
fprintf(stderr, "unable to create listener - %s\n", \
args.errorMessage);
fflush(stderr);
nzaeconptClose(hConpt);
return -1;
}
NZAEREMPROT_HANDLE hRemprot = args.handle;
NzaeApi api;
int i;
for (i = 0; i < 5; i++)
{
if (nzaeRemprotAcceptApi(hRemprot, &api))
{
fprintf(stderr, "unable to accept API - %s\n", \
nzaeRemprotGetLastErrorText(hRemprot));
fflush(stderr);
nzaeconptClose(hConpt);
nzaeRemprotClose(hRemprot);
return -1;
}
if (api.apiType != NZAE_API_FUNCTION)
{
fprintf(stderr, "unexpected API returned\n");
fflush(stderr);
nzaeconptClose(hConpt);
nzaeRemprotClose(hRemprot);
return -1;
}
printf("testcapi: accepted a remote request\n");
fflush(stdout);
run(api.handle.function);
}
nzaeRemprotClose(hRemprot);
nzaeconptClose(hConpt);
}
return 0;
}
static void validateRuntime(NZAE_HANDLE handle, NzaeRuntime *aeRun, int64_t \
*args, int type)
{
// argss:
// dataslice, transaction, hardware, numslices, numspus, locus
int64_t dataslice = args[0];
int64_t txid = args[1];
int64_t hwid = args[2];
int64_t nslices = args[3];
int64_t nspus = args[4];
int64_t locus = args[5];
char buf[1024];
if (locus != (int64_t)aeRun->locus)
{
sprintf(buf, "test fails: 1\n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
if (aeRun->suggestedMemoryLimit != 123)
{
sprintf(buf, "test fails: 7 \n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
if (aeRun->userQuery == false)
{
sprintf(buf, "test fails: 8 \n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
if (type != (int64_t)aeRun->adapterType)
{
sprintf(buf, "test fails: 9 \n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
if (locus == (int64_t)NZAE_LOCUS_POSTGRES)
{
return;
}
if (dataslice != (int64_t)aeRun->dataSliceId)
{
sprintf(buf, "test fails: 2 \n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
if (txid != 0 && txid != (int64_t)aeRun->transactionId)
{
sprintf(buf, "test fails: 3 \n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
if (hwid != (int64_t)aeRun->hardwareId)
{
sprintf(buf, "test fails: 4 \n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
if (nslices != (int64_t)aeRun->numberDataSlices)
{
sprintf(buf, "test fails: 5 \n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
if (nspus != (int64_t)aeRun->numberSpus)
{
sprintf(buf, "test fails: 6 \n");
nzaeLog(handle,NZAE_LOG_DEBUG, buf);
}
}
static int run(NZAE_HANDLE h)
{
NzaeMetadata metadata;
if (nzaeGetMetadata(h, &metadata))
{
fprintf(stderr, "get metadata failed\n");
return -1;
}
#define CHECK(value) \
{ \
NzaeRcCode rc = value; \
if (rc) \
{ \
const char * format = "%s in %s at %d"; \
fprintf(stderr, format, \
nzaeGetLastErrorText(h), __FILE__, __LINE__); \
nzaeUserError(h, format, \
nzaeGetLastErrorText(h), __FILE__, __LINE__); \
exit(-1); \
} \
}
for (;;)
{
int64_t ar[6];
int i;
double result = 0;
NzaeRcCode rc = nzaeGetNext(h);
if (rc == NZAE_RC_END)
{
break;
}
NzudsData * input = NULL;
for (i=0; i < 6; i++) {
CHECK(nzaeGetInputColumn(h, i, &input));
if (input->type == NZUDSUDX_INT32)
{
ar[i] = *input->data.pInt32;
}
else if (input->type == NZUDSUDX_INT64)
{
ar[i] = *input->data.pInt64;
}
}
NzaeRuntime aeRun;
nzaeGetRuntime(h,&aeRun);
validateRuntime(h, &aeRun, ar, NZAE_ADAPTER_UDTF);
CHECK(nzaeSetOutputString(h, 0, "done"));
CHECK(nzaeOutputResult(h));
}
nzaeDone(h);
return 0;
}
Compilation
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language system --version 3 \
--template compile log.c --exe logRegistration
Register the example using the --mem and --mask options. The --mask option enables logging for DEBUG and the --mem option sets the memory runtime information.
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --language system --version 3 \
--template udtf --exe log \
--sig "runtime_c(int8,int8,int8,int8,int8,int8)" \
--return "table(output varchar(100))" --mask debug --mem 123
Running
Before running, enable logging by running nzudxdbg:
nzudxdbg
Processing 1 spus
.
done
Processing host
done
Then run the SQL:
SELECT * FROM TABLE WITH FINAL(runtime_c(1,1,1,1,1,1));
OUTPUT
--------
done
(1 row)
The NPS system logging appears in the window where the NPS system was started:
05-03-10 15:03:12 (dbos.18728) [d,udx ] test fails: 2
05-03-10 15:03:12 (dbos.18728) [d,udx ] test fails: 3
05-03-10 15:03:12 (dbos.18728) [d,udx ] test fails: 4
This is the expected output since the arguments specified did not match the runtime in those cases.