DG consumer API work, formatting details
authorMichal Voců <michal@ruk.cuni.cz>
Wed, 6 Aug 2008 15:19:54 +0000 (15:19 +0000)
committerMichal Voců <michal@ruk.cuni.cz>
Wed, 6 Aug 2008 15:19:54 +0000 (15:19 +0000)
org.glite.lb.doc/examples/client_headers.h [deleted file]
org.glite.lb.doc/examples/example1.c
org.glite.lb.doc/examples/example1_code.c [deleted file]
org.glite.lb.doc/examples/prod_example1.c
org.glite.lb.doc/src/LBDG-Introduction.tex
org.glite.lb.doc/src/LBDG.tex
org.glite.lb.doc/src/consumer_api.tex
org.glite.lb.doc/src/producer_api.tex

diff --git a/org.glite.lb.doc/examples/client_headers.h b/org.glite.lb.doc/examples/client_headers.h
deleted file mode 100644 (file)
index c4cd498..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#include "glite/lb/context.h"
-#include "glite/lb/xml_conversions.h"
-#include "glite/lb/consumer.h"
-
index a26c451..9857036 100644 (file)
@@ -5,16 +5,45 @@
 #include <string.h>
 #include <expat.h>
 
-#include "client_headers.h"
-
+#include "glite/lb/context.h"
 #include "glite/lb/xml_conversions.h"
+#include "glite/lb/consumer.h"
 
 extern void print_jobs(edg_wll_JobStat *);
 
 int main(int argc,char **argv)
 {
 
-#include "example1_code.c"
-
+       edg_wll_Context     ctx;    
+       edg_wll_JobStat    *statesOut = NULL;
+       edg_wll_QueryRec    jc[2];
+       
+       edg_wll_InitContext(&ctx);
+       
+       jc[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
+       jc[0].op = EDG_WLL_QUERY_OP_EQUAL;
+       if ( edg_wlc_JobIdParse(
+                    "https://lhun.ics.muni.cz:9000/OirOgeWh_F9sfMZjnIPYhQ",
+                    &jc[0].value.j) )
+       {
+               edg_wll_FreeContext(ctx);
+               exit(1);
+       }
+       jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+       if (edg_wll_QueryJobs(ctx, jc, 0, NULL, &statesOut)) {
+               char    *err_text,*err_desc;
+               
+               edg_wll_Error(ctx,&err_text,&err_desc);
+               fprintf(stderr,"QueryJobs: %s (%s)\n",err_text,err_desc);
+               free(err_text);
+               free(err_desc);
+       }
+       else {
+               print_jobs(statesOut);  /* process the returned data */
+               edg_wll_FreeStatus(statesOut);
+               free(statesOut);
+       }
+       edg_wlc_JobIdFree(jc[0].value.j);
+       edg_wll_FreeContext(ctx);
        return 0;
 }
diff --git a/org.glite.lb.doc/examples/example1_code.c b/org.glite.lb.doc/examples/example1_code.c
deleted file mode 100644 (file)
index e12a1b7..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-edg_wll_Context     ctx;    
-edg_wll_JobStat    *statesOut = NULL;
-edg_wll_QueryRec    jc[2];
-
-edg_wll_InitContext(&ctx);
-
-jc[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
-jc[0].op = EDG_WLL_QUERY_OP_EQUAL;
-if ( edg_wlc_JobIdParse(
-            "https://lhun.ics.muni.cz:9000/OirOgeWh_F9sfMZjnIPYhQ",
-            &jc[0].value.j) )
-{
-       edg_wll_FreeContext(ctx);
-       exit(1);
-}
-jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
-if (edg_wll_QueryJobs(ctx, jc, 0, NULL, &statesOut)) {
-       char    *err_text,*err_desc;
-       
-       edg_wll_Error(ctx,&err_text,&err_desc);
-       fprintf(stderr,"QueryJobs: %s (%s)\n",err_text,err_desc);
-       free(err_text);
-       free(err_desc);
-}
-else {
-       print_jobs(statesOut);  /* process the returned data */
-       edg_wll_FreeStatus(statesOut);
-       free(statesOut);
-}
-edg_wlc_JobIdFree(jc[0].value.j);
-edg_wll_FreeContext(ctx);
index d78b072..9e8d911 100644 (file)
@@ -5,9 +5,12 @@
 #include <string.h>
 #include <errno.h>
 
-#include "glite/jobid/cjobid.h"
+/*headers*/
+#include "glite/jobid/cjobid.h" 
 #include "glite/lb/events.h"
-#include "glite/lb/producer.h"
+#include "glite/lb/producer.h" 
+/*end headers*/
+
 
 static struct option opts[] = {
        {"help",                0,      NULL,   'h'},
@@ -63,24 +66,28 @@ int main(int argc, char *argv[])
 
        if ( (errno = edg_wlc_JobIdParse(jobid_s, &jobid)) ) { perror(jobid_s); return 1; }
 
+       /*context*/
        edg_wll_InitContext(&ctx);
-
+       
        edg_wll_SetParam(ctx, EDG_WLL_PARAM_SOURCE, EDG_WLL_SOURCE_USER_INTERFACE);
        edg_wll_SetParam(ctx, EDG_WLL_PARAM_HOST, server);
        edg_wll_SetParam(ctx, EDG_WLL_PARAM_PORT, port);
+       /*end context*/
 
+       /*sequence*/
        if (edg_wll_SetLoggingJob(ctx, jobid, seq_code, EDG_WLL_SEQ_NORMAL)) {
                char    *et,*ed;
                edg_wll_Error(ctx,&et,&ed);
                fprintf(stderr,"SetLoggingJob(%s,%s): %s (%s)\n",jobid_s,seq_code,et,ed);
                exit(1);
        }
+       /*end sequence*/
 
-       err = edg_wll_LogEvent(ctx,
+       /*log*/
+       err = edg_wll_LogEvent(ctx, //* \label{l:logevent}
                               EDG_WLL_EVENT_USERTAG, 
                               EDG_WLL_FORMAT_USERTAG,
                               name, value);
-
        if (err) {
            char        *et,*ed;
 
@@ -89,6 +96,7 @@ int main(int argc, char *argv[])
                    argv[0],et,ed);
            free(et); free(ed);
        }
+       /*end log*/
 
        seq_code = edg_wll_GetSequenceCode(ctx);
        puts(seq_code);
index b40aafd..80465c4 100644 (file)
@@ -24,6 +24,12 @@ functions which we will describe first. Most of common data types and
 functions are separated in its own SW module called
 \verb'org.glite.lb.common' and are described in section~\ref{s:common}
 
+\marginpar{Example code}%
+Source code for examples shown in this guide is distributed together
+with the document. The examples contain excerpts from the actual files
+with reference to the file name and line numbers. All the examples can
+be compiled using attached Makefile.
+
 \marginpar{Recommended reading}%
 Before you start reading this guide, it is recommended to accomodate
 yourself with the \LB architecture described in the first part of the
@@ -88,7 +94,7 @@ The return type of most of the API functions is \verb'int'.
 Unless specified otherwise, zero return value means success, non-zero
 failure. Standard error codes from \verb'errno.h' are used as
 much as possible. In a few cases the error can not be intuitively
-mapped and \LB specific error value greater than
+mapped into standard code and \LB specific error value greater than
 \verb'EDG_WLL_ERROR_BASE' is returned.
 
 Few API function return \verb'char *'. In such a~case
@@ -97,7 +103,8 @@ Few API function return \verb'char *'. In such a~case
 \subsection{Context and Parameter Settings}
 \label{s:context}
 
-The \LB library does not maintain internal state (apart of network connections, see \ref{s:pool}), all the API
+The \LB library does not maintain internal state (apart of network
+connections, see \ref{s:pool}), all the API 
 functions refer to a~\emph{context} argument instead.
 Context object preserves state information among the various API
 calls, the state including \LB library parameters (\eg security
@@ -183,16 +190,26 @@ parameter; parameters specific for producer and consumer API are
 described in respective API sections, the common parameters are:
 
 \begin{table}[h]
-\begin{tabularx}{\textwidth}{llX}
-{\bf C name} & {\bf Env. variable} & {\bf Description} \\
+\begin{tabularx}{\textwidth}{lX}
+{\bf C name} & {\bf Description} \\
 \hline
-\lstinline'EDG_WLL_PARAM_X509_KEY' & \lstinline'X509_USER_KEY' & Key file to use for
-authentication. \\
-\lstinline'EDG_WLL_PARAM_X509_CERT' & \lstinline'X509_USER_CERT' & Certificate file to use
-for authentication. \\
-\lstinline'EDG_WLL_PARAM_CONNPOOL_SIZE' & & Maximum number
-of open connections maintained by the library. \\
+\lstinline'EDG_WLL_PARAM_X509_KEY' & 
+Key file to use for authentication. 
+\par {\it Type: } \lstinline'char *'
+\par {\it Env. variable: } \lstinline'X509_USER_KEY'  
+\\
+\lstinline'EDG_WLL_PARAM_X509_CERT' &   
+Certificate file to use for authentication. 
+\par {\it Type: } \lstinline'char *'
+\par {\it Env. variable: } \lstinline'X509_USER_CERT'
+\\
+\lstinline'EDG_WLL_PARAM_CONNPOOL_SIZE' & 
+Maximum number of open connections maintained by the library. 
+\par {\it Type: } \lstinline'int'
+\\
 \end{tabularx}
+\caption{Common context parameters}
+\label{t:cparam}
 \end{table}
 
 The third argument is parameter value, which can be of type
@@ -243,7 +260,7 @@ identifier of the job (see also \cite{lbug}). The type representing
 the JobId is opaque \verb'glite_jobid_t'. The JobId is in fact
 just URL with \verb'https' protocol, path component being unique string
 with no further structure and host and port designating the \LB server
-holding the job information. The JobId can be
+holding the job information. The JobId can be:
 \begin{itemize}
 \item created new for given \LB server (the unique part will be
 generated by the \LB library):
@@ -258,6 +275,8 @@ if(ret = glite_jobid_create("some.host", 0, &jobid)) {
 read from file):
 \begin{lstlisting}[firstnumber=3]
 if(ret = glite_jobid_parse("https://some.host:9000/OirOgeWh_F9sfMZjnIPYhQ", &jobid)) {
+       fprintf(stderr, "error parsing jobid: %s\n", strerror(ret));
+}
 \end{lstlisting}
 \item or obtained as part of \LB server query result.
 \end{itemize}
@@ -271,8 +290,8 @@ For more information see file \verb'glite/jobid/cjobid.h'
 \marginpar{\textbf{\LB 1.x}}%
 {\it In the older \LB versions (1.x) the
 structure was named \verb'edg_wlc_JobId' and the functions had prefix
-\verb'edg_wlc_JobId'. Exact description can be found in the
-header file \verb'glite/wmsutils/cjobid.h'}
+\verb'edg_wlc_JobId', \eg\verb'edg_wlc_JobIdFree()'. Exact description
+can be found in the header file \verb'glite/wmsutils/cjobid.h'}
 
 
 \subsubsection{Event}
index d24bca2..0db8778 100644 (file)
@@ -27,6 +27,9 @@
 \begin{document}
 \reversemarginpar
 \lstset{language=C,basicstyle=\footnotesize,numbers=none,breaklines=true}
+\lstset{title=\lstname}
+\lstset{rangeprefix=/*,rangesuffix=*/,includerangemarker=false}
+\lstset{escapeinside={//*}{\^^M}}
 
 % ----- BEGIN COPY -----
 % copied from org.glite.lb.client/doc/api/api.tex in hope it could be useful
index 1946d89..c824e35 100644 (file)
@@ -1,72 +1,27 @@
 % -*- mode: latex -*-
 
 \section{\LB\ Querying (Consumer) API}
-\TODO{Complete review; create really functional (buildable) examples and use verbatiminput of relevant part of the code; add list of header files, important functions and data types and their description, etc.}
-
-\def\partitle#1{\par{\textbf{#1}}\par}
 
 \label{ConsOview}
-This section describes the aspects of principal use of the \LB\ consumer API.
-It begins with the simplest examples how to query the bookkeeping
-service, continues with various selection criteria and their combinations, and
-through queries on user tags and timestamps it concludes with the discussion of
-application specific queries.
-
-The document is intended for users interested in the \LB\
-consumer API or those interested in better understanding of the \LB\ service 
-capabilities.
-
-In the presented examples only the C \LB\ API (Sect.~\ref{query-C}) is considered.
-The C++ API (Sect.~\ref{query-CPP})  covers the same functionality.
-
-\subsection{Header files}
 
-Job.h
-JobStatus.h.T
-Notification.h
-ServerConnection.h
-connection.h
-consumer.h
-notification.h
-prod\_proto.h
-producer.h.T
-statistics.h
+\subsection{Query Language}
 
-\verbatiminput{client_headers.h}
+\subsection{C Language Binding}
 
-\subsection{Returned results}
-
-\LB\ server returns errors which are classified as hard and soft errors.
-The main difference between these categories is that in the case of soft
-errors results may still be returned.
-The authorization errors belong to
-``soft error'' sort. Hard errors are typically all unrecoverable errors like ENOMEM.
+\subsubsection{Call Semantics}
 
 When the item count returned by \LB\ server exceeds the defined limits, the E2BIG error occur.
 There are two limits\,---\,the server and the user limit. The user defined limit may be set in
 the context at the client side in the following way:
-\begin{verbatim}
-  #include <glite/lb/context.h>
-  ...
-  edg_wll_Context     ctx;    
-
-  edg_wll_InitContext(&ctx);
-  edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_JOBS_LIMIT, 10);
-  edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_EVENTS_LIMIT, 20);
-  edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_RESULTS, 30);
-  ...
-  edg_wll_FreeContext(ctx);
-\end{verbatim}
-This code sets the user query limits to the given maximal count of items.
 
-The E2BIG error may fall into both categories depending on the setting of
-another context parameter, EDG\_WLL\_PARAM\_QUERY\_RESULTS.
-It may take the following values:
+\subsubsection{Header Files}
+\begin{table}[h]
+\begin{tabularx}{\textwidth}{>{\tt}lX}
+glite/lb/consumer.h & Prototypes for all query functions. \\
+\end{tabularx}
+\end{table}
 
-%The E2BIG error can be classified as hard or soft error too because this error can be affected
-%by one more parameter which can make this error hard or soft. This parameter can be set like this:\\
-%\texttt{edg\_wll\_SetParam(ctx, EDG\_WLL\_PARAM\_QUERY\_RESULTS, EDG\_WLL\_QUERYRES\_ALL);}
-%and possible values follows:
+\subsubsection{Context Parameters}
 \begin{itemize}
        \item{EDG\_WLL\_QUERYRES\_NONE}\,---\,No results are returned.
        In this case an E2BIG error acts like a hard error.
@@ -78,14 +33,19 @@ It may take the following values:
 \end{itemize}
 Default value is EDG\_WLL\_QUERYRES\_NONE.
 
-\TODO{zkratit, doplnit zpracovani struktury (print jobs)}
+\subsubsection{Return Values}
+\LB\ server returns errors which are classified as hard and soft errors.
+The main difference between these categories is that in the case of soft
+errors results may still be returned.
+The authorization errors belong to
+``soft error'' sort. Hard errors are typically all unrecoverable errors like ENOMEM.
 
-\subsection{Job queries}
+The E2BIG error may fall into both categories depending on the setting of
+another context parameter, EDG\_WLL\_PARAM\_QUERY\_RESULTS.
+It may take the following values:
 
-\partitle{Job status}
-\label{JS}
 
-\TODO{Add edg\_wll\_JobStat description and error codes handling}
+\subsubsection{Job Queries}
 
 The simplest case corresponds to the situation when an exact job ID
 is known and the only information requested is the job status. The job ID
@@ -95,46 +55,6 @@ all the relevant structures and API calls to retrieve status information
 about a job with the ID\\
 \texttt{https://lhun.ics.muni.cz:9000/OirOgeWh\_F9sfMZjnIPYhQ}.
 
-\lstinputlisting{example1_code.c}
-
-%\verbatiminput{example1_code.c}
-
-%\begin{verbatim}
-%  #include <glite/lb/consumer.h>
-%  ...
-%  edg_wll_Context     ctx;    
-%  edg_wll_JobStat    *statesOut = NULL;
-%  edg_wll_QueryRec    jc[2];
-%  ...
-%  edg_wll_InitContext(&ctx);
-%  ...
-%  jc[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
-%  jc[0].op = EDG_WLL_QUERY_OP_EQUAL;
-%  if ( edg_wlc_JobIdParse(
-%    "https://lhun.ics.muni.cz:9000/OirOgeWh_F9sfMZjnIPYhQ",
-%     &jc[0].value.j) )
-%  {
-%     edg_wll_FreeContext(ctx);
-%     exit(1);
-%  }
-%  jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
-%  if (edg_wll_QueryJobs(ctx, jc, 0, NULL, &statesOut)) {
-%    char    *err_text,*err_desc;
-%
-%    edg_wll_Error(ctx,&err_text,&err_desc);
-%    fprintf(stderr,"QueryJobs: %s (%s)\n",err_text,err_desc);
-%    free(err_text);
-%    free(err_desc);
-%  }
-%  else {
-%    ...       /* process the returned data */
-%    edg_wll_FreeStatus(statesOut);
-%    free(statesOut);
-%  }
-%  edg_wlc_JobIdFree(jc[0].value.j);
-%  edg_wll_FreeContext(ctx);
-%\end{verbatim}
-
 The first function call in this example initializes the \LB\ context\,---\,variable
 \texttt{ctx}\,---\,which is necessary for later use. The most important part
 of this code fragment is the \texttt{jc} variable setting.
@@ -152,7 +72,7 @@ management\,---\,deallocation of data that are not needed anymore.
 \emph{For the sake of simplicity such code is not included in the examples
 in the rest of this document.}
 
-\partitle{All user's jobs}
+%\partitle{All user's jobs}
 \label{JQ-auj}
 
 \TODO{Update the example so that it is really working}
@@ -195,7 +115,7 @@ Developers should keep in mind that the output of such a query could be really h
 The following examples demonstrates how \texttt{edg\_wll\_QueryJobs()} combines 
 the given conditions in a logical conjugation.
 
-\partitle{Running jobs}
+%\partitle{Running jobs}
 \label{JQ-rj}
 
 If all (user's) running jobs are to be retrieved the following code can
@@ -224,7 +144,7 @@ This example combines previous example with a new criteria. There are used two d
 \texttt{edg\_wll\_QueryJobs()} connects them in the logical conjunction.
 Examples using logical conjunction and logical disjunction are shown in the Sect.~\ref{JQ-AO}.
 
-\partitle{Jobs running at a given CE}
+%\partitle{Jobs running at a given CE}
 The following example gives description of all (user's) jobs running at CE XYZ.
 \begin{verbatim}
   #include <glite/lb/consumer.h>
@@ -252,7 +172,7 @@ In a case the job is not running the destination (attribute \texttt{EDG\_WLL\_QU
 saves a CE name the job will be routed to. If location is needed use the \texttt{EDG\_WLL\_QUERY\_ATTR\_LOCATION} attribute.
 
 
-\partitle{The WITHIN operator}
+%\partitle{The WITHIN operator}
 The \texttt{EDG\_WLL\_QUERY\_OP\_WITHIN} operator can be used in any condition with numeric values.
 The following example shows a query on all user's jobs that have returned 
 an exit code from 2 to 7.
@@ -285,7 +205,7 @@ The last attribute (``exit code'') uses the WITHIN operator. The WITHIN operator
 interval\,---\,the lower bound of the interval is stored in the \texttt{value} union and the
 upper bound is stored in the \texttt{value2} union.
 
-\partitle{Using AND, OR in query clauses}
+%\partitle{Using AND, OR in query clauses}
 \label{JQ-AO}
 In many cases the basic logic using only conjunctions is not sufficient.
 For example, if you need all your jobs running at the destination XXX or at
@@ -345,7 +265,7 @@ This query equals to the formula
 \texttt{(user=NULL) and (state=Running) and (dest='XXX' or dest='YYY')}.
 \end{quote}
 
-\partitle{User tags}
+%\partitle{User tags}
 \label{JQ_ut}
 \TODO{Is it really working?}
 User tags can be used for marking (labelling) jobs. A user tag is
@@ -427,7 +347,7 @@ or-clause.
 %That means that user tags are composed of two variable components
 %and user tag indices depend on tag names.
 
-\partitle{Time attributes}
+%\partitle{Time attributes}
 
 %A time interval in which a particular state appears is attached to every job
 %state.
@@ -490,7 +410,7 @@ interval.
 \TODO{pro prehlednost bych mozna pridal seznam vsech atributu
 na ktere se lze ptat}
 
-\subsection{Event queries and application specific queries}
+\subsubsection{Event queries and application specific queries}
 \label{ASQ}
 Event queries and job queries are similar. 
 Obviously, the return type is different\Dash the \LB\ raw events.
@@ -501,7 +421,7 @@ Some examples showing event queries
 are considered in the following paragraph.
 
 
-\partitle{All jobs marked as red}
+%\partitle{All jobs marked as red}
 \label{ASQ_allred}
 This example shows how to select all user's jobs which were (at some time)
 marked with the value red of user tag color.
@@ -545,7 +465,7 @@ changed afterwards or not (unlike straightforward \texttt{edg\_wll\_QueryJobs()}
 which considers the ``current color'' only). The same applies on all
 subsequent examples using the user's marking.
 
-\partitle{All red jobs at some time marked as green}
+%\partitle{All red jobs at some time marked as green}
 The next example shows how to select all jobs which are just now marked with
 user tag color red, but at some time in the past they were marked as green.
 \begin{verbatim}
@@ -574,7 +494,7 @@ Jobs conditions selects all jobs with tag ``color = red'' (See example in paragr
 \ref{JQ_RedJobs}). Event conditions selects all jobs which were sometimes marked
 as green\,---\,this is described in previous example \ref{ASQ_allred}.
 
-\partitle{All resubmitted jobs}
+%\partitle{All resubmitted jobs}
 The next example shows how to get all (your) resubmitted jobs.
 \begin{verbatim}
   #include <glite/lb/consumer.h>
@@ -596,7 +516,7 @@ The next example shows how to get all (your) resubmitted jobs.
   ...
 \end{verbatim}
 
-\partitle{Jobs resubmitted in the last two hours}
+%\partitle{Jobs resubmitted in the last two hours}
 The next example shows how to get all user's jobs which were resubmitted in the last
 2 hours.
 \begin{verbatim}
@@ -623,7 +543,7 @@ The next example shows how to get all user's jobs which were resubmitted in the
 \end{verbatim}
 
 
-\partitle{Complex query}
+%\partitle{Complex query}
 The last example illustrates the API usage on
  a~meaningful but rather complex query ``which of my red jobs are heading  
 to a~destination that already encountered problems executing red jobs''.
index 653a7d0..ef8960a 100644 (file)
@@ -109,22 +109,21 @@ server or proxy.
 The synchronous variants of logging functions can in addition return
 \verb'EDG_WLL_ERROR_NOJOBID' or \verb'EDG_WLL_ERROR_DB_DUP_KEY'.
 
-\subsubsection{Logging events}
-\TODO{odkaz na soubor}
-In this section we will give an example how to log an UserTag event to
+\subsubsection{Logging event example}
+In this section we will give commented example how to log an UserTag event to
 the \LB.
 
 First we have to include neccessary headers:
-\lstinputlisting[firstline=8,lastline=10]{prod_example1.c}
+\lstinputlisting[numbers=left,linerange=headers-end\ headers]{prod_example1.c}
 
 Initialize context and set parameters:
-\lstinputlisting[firstline=61,lastline=84]{prod_example1.c}
+\lstinputlisting[numbers=left,linerange=context-end\ context]{prod_example1.c}
 
 \TODO{proper setting of sequence codes}
-\lstinputlisting[firstline=86,lastline=91]{prod_example1.c}
+\lstinputlisting[numbers=left,linerange=sequence-end\ sequence]{prod_example1.c}
 
 Log the event:
-\lstinputlisting[firstline=93,lastline=107]{prod_example1.c}
+\lstinputlisting[numbers=left,linerange=log-end\ log]{prod_example1.c}
 
 The \verb'edg_wll_LogEvent()' function is defined as follows:
 \begin{lstlisting}[numbers=none]
@@ -138,9 +137,9 @@ string and corresponding arguments yourself. The UserTag event has
 only two arguments, tag name and value, but other events require more
 arguments. 
 
-Instead of using the generic \verb'edg_wll_LogEvent()', we could also
+Instead of using the generic \verb'edg_wll_LogEvent()' at line~\ref{l:logevent}, we could also
 write:
-\begin{lstlisting}[firstnumber=92]
+\begin{lstlisting}
 err = edg_wll_LogUserTag(ctx, name, value);
 \end{lstlisting}