oml2-scaffold(1)
================

NAME
----
oml2-scaffold - OML2 instrumentation code generator

SYNOPSIS
--------
[verse]
*oml2-scaffold* [OPTIONS] [--oml|--opts|--main|--make] 'appfile'
*oml2-scaffold* [OPTIONS] --app 'appname'

DESCRIPTION
-----------

*oml2-scaffold* generates skeleton OML application source code based
on a template provided by the user (the file named 'appfile'). When
invoked with the *--oml* options, a C header is generated describing
the application's OML measurement points and providing helper
functions based on linkoml:omlc_inject[3] for each of them; when
*--opts* is used, another C header is generated that describes the
command line options that the program accepts, using the functions and
data structures provided by the linkman:popt[3] library; when *--main* is
used, a C file is generated that provides a skeleton *main*() function
and run loop, with an example of how to inject measurement samples
using the helpers functions defined in the header for every defined
measurement point; and when *--make* is used, *oml2-scaffold* creates
a Makefile that can be used to build the generated program.

In fact, the generated program can be built and run as-is with no
further modifications required.  This can serve as an example OML
application to play with, however the data that it measures is
not very interesting.  The programmer must supply that part of the
application, unfortunately.

OPTIONS
-------
*oml2-scaffold* recognises the following command line options:

--oml::
Create OML header file 'APPNAME_oml.h' defining all measurement points,
as well as registration and injection helper functions
(linkomlalias:oml_register_mps[liboml2,3] and
linkomlalias:oml_inject_MPNAME[liboml2,3]). The registration helper is
only available when defining linkman:cpp[1] macro 'OML_FROM_MAIN' prior
to the '#include' statement for 'APPNAME_oml.h'.  This should only be
done in the file calling linkomlalias:oml_register_mps[liboml2,3]
(usually in the *main*() function).

--opts::
Create the linkman:popt[3] header file 'APPNAME_popt.h' for
application command-line parsing.

--make::
Create a skeleton Makefile for this application.

--main::
Create skeleton main file 'APPNAME.c' for this application.

-a::
--app 'name'::
Create a skeleton application definition file 'name.rb' for an
application with the given 'name'. Other files generated from this
application definition will use 'name' as 'APPNAME'.

-f::
--force::
Do not check if a file would be overwritten.  Otherwise
*oml2-scaffold* checks for an existing file before trying to write to it,
and aborts if it already exists.

-l::
--long::
Use the ':long' type as the underlying type for the ':int' and
':integer' aliases.  This overrides the default of ':int32'

-i::
--int32::
Use the ':int32' type as the underlying type for the ':int', ':integer'
and ':long' aliases. This is the default behaviour.

-v::
--version::
Print the version number of *oml2-scaffold*.

-h::
--help::
Print a brief usage message.

It is permitted to issue multiple of *--oml*, *--opts*, *--main*, and
*--make* on the same command line.

TEMPLATE LANGUAGE
-----------------

The template language is based on Ruby syntax.  Here is a simple
example:

--------
defApplication('oml:man:foo', 'foo') do |app|
  app.version(1,0)
  app.shortDescription = "Monitoring the system's foo"
  app.description = %{
'foo' is an application to measure the 'foo' of a network and
its computers. }
  app.path = "/PATH/TO/BINARY"

  app.defProperty('cpu', 'Report CPU foo', '-c',
               :type => :boolean, :var_name => 'report_cpu')
  app.defProperty('mem', 'Report memory foo', "--mem",
               :type => :boolean, :unit => "bytes",
	       :mnemonic => 'm',
	       :var_name => 'report_memory')

  app.defMeasurement("memory") do |mp|
    mp.defMetric('ram', :string)
    mp.defMetric('total', :uint32)
    mp.defMetric('free', :uint32)
    mp.defMetric('used', :uint32)
    mp.defMetric('free_percent', :double)
    mp.defMetric('used_percent', :double)
  end

  app.defMeasurement("cpu") do |mp|
    mp.defMetric('user', :uint64)
    mp.defMetric('sys', :uint64)
    mp.defMetric('nice', :uint64)
    mp.defMetric('idle', :uint64)
    mp.defMetric('wait', :uint64)
    mp.defMetric('irq', :uint64)
    mp.defMetric('soft_irq', :uint64)
    mp.defMetric('stolen', :uint64)
    mp.defMetric('total', :uint64)
  end
end
--------

The 'defApplication' command begins the template, and it takes two
arguments:  a 'uri' and a 'name'.  It also takes a Ruby block that
can create the features of the application.  The 'uri' must be a
string containing a colon-separated set of components.  The 'uri' is
mandatory, but the 'name' is optional.  If the 'name' is not supplied
then it is taken from the final component of the 'uri'.  For example,

--------
defApplication('oml:man:bar') do |a|
...
end
--------

will create an application named 'bar'.  The application name is used
to name the files that *oml2-scaffold* generates.  Note that
'defApplication' must be followed by a block in either of Ruby's two
syntaxes for blocks, either using do...end as above, or the C-like
curly brace syntax:

--------
defApplication('oml:man:bar') { |a|
...
}
--------

The 'defApplication' block is given an application object as a parameter
(that's the do |a| part).  The application object supports a number of
operations that are described below.

app.version(major, minor = 0, revision = 0)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The 'version' command specifies the application's version number.  The
'minor' and 'revision' can be omitted.  The arguments are assumed to
be integers.  The version information is output as a string in the
file 'version.h'.  As an example, the following version declaration:

--------
app.version(2, 4, 0)
--------

will result in a 'version.h' file containing the following C
preprocessor #define:

--------
#define VERSION "2.4.0"
--------

app.shortDescription = <string>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This should be a one-line description of the application.

app.description = <string>
~~~~~~~~~~~~~~~~~~~~~~~~~~

This should be a longer description of the application.  It can use
Ruby's multi-line string syntaxes to allow a string that breaks over
multiple lines, as in the example above.

app.path = <string>
~~~~~~~~~~~~~~~~~~~

This is the path where the application is expected to be installed. This
is particularly useful when generationg the Makefile with the *--make*
option. OMF also uses this information.

app.defProperty(name, description, parameter, options = {})
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The 'defProperty' command provides a way to describe the options that
the program accepts on the command line.  The code generated by the
*--opts* option to *oml2-scaffold* uses the 'defProperty' commands to
construct a linkman:popt[3] table and function to parse the options that
they define.

The 'name' parameter identifies the option.

The 'description' parameter is used by linkman:popt[3] when generating
the help message for the *--help* option ('descrip').

The 'parameter' is the string that needs to be added before introducing
the option. It can be either a short of a long option depending on how
many dashes prefix it.

One dash::
'-' identifies a single-letter parameter. The following character will
be used as the 'shortName' by linkman:popt[3] (in this case, 'longName'
is taken to be 'name').

Two dashes::
*--* identifies a long option. The following string will be used as the
'longName' by linkman:popt[3] (in this case, 'shortName' is taken to be
the same as ':mnemonic' below, or nothing).

The 'options' parameter should be a Ruby hash, but can be introduced
straight after the above options. It allows the user to describe further
behaviour for the option. The possible keys are as follows.

*:type*:: The ':type' option specifies what type of argument this option accepts.
If ':type' is omitted then ':int' is assumed.  The ':type' option
should be one of:

':boolean';;
This property is a flag that can be represented as a boolean value; it
does not require an argument.  For instance, a '-q' option for
enabling a quiet mode of operation could use the ':boolean' option.
':flag' is a deprecated OMF-incompatible synonym.

':string';;
This property accepts a string argument.

':int';;
':integer';;
':long';;
':long_long';;
This property accepts an integer argument that is either a C 'int', a
C 'long', or a C 'long long' value. The ':integer' variant is a synonym
for ':int'.

':double';;
':float';;
This property accepts a floating point argument that is either a C
'double' or a C 'float'. When in doubt, prefer 'double'.

*:mnemonic*:: A character which is returned by linkman:popt[3]'s
'poptGetNextOpt' when this option is found. When 'parameter' starts
with two dashes, the *:mnemonic* is also used as the 'shortName'.

*:unit*:: The unit for this property.  This is used by linkman:popt[3] when generating
the help message for the *--help* option ('argDescrip').

*:default*:: A default value for this property if it is not specified on the
command line by the user of the application.

*:var_name*:: Used to name the C variable that will store the value of
this command line option's argument. Otherwise a sanitised version of
the 'name' is used. The option arguments are all stored in
variables within the 'g_opts_storage' struct in the generated C program.

app.defMeasurement(name)
~~~~~~~~~~~~~~~~~~~~~~
The 'defMeasurement' command defines a new, named measurement point.
(For more information about what a measurement point is, see
linkoml:liboml2[1] and linkoml:liboml2[3].)  The command accepts a block that
takes a single parameter, the MP itself; this block is used to
define the fields of the measurement point.  Each field is defined
using the 'defMetric' command.

mp.defMetric(name, type)
~~~~~~~~~~~~~~~~~~~~~~~
'defMetric' defines a single field of a measurement point.  Each field
must have a 'name' and a 'type'.  The 'type' must be a string equal to
one of the following, which correspond with the defined OML types:

*:int32*::
This field will record 32-bit signed integer data. ':long' is a
deprecated synonym. ':int' and ':integer' also map to this type, but
their use is not recommended.

*:uint32*::
This field will record 32-bit unsigned integer data.

*:int64*::
This field will record 64-bit signed integer data.

*:uint64*::
This field will record 64-bit unsigned integer data.

*:double*::
This field will record floating point data in C 'double' format.
':float' and ':real' are deprecated synonyms.

*:string*::
This field will record string data.

*:blob*::
This field will record binary data.

*:guid*::
This field will record a globally unique identifier allowing to group
tuples together, or to link them accross 'MPs'. See
linkomlalias:omlc_guid_generate[liboml2,3] for more details.

*:boolean*::
This field will record a boolean value.

*:vector_int32*::
This field will hold a vector of 32-bit signed integer values.

*:vector_uint32*::
This field will hold a vector of 32-bit unsigned integer values.

*:vector_int64*::
This field will hold a vector of 64-bit signed integer values.

*:vector_uint64*::
This field will hold a vector of 64-bit unsigned integer values.

*:vector_double*::
This field will hold a vector of C 'double' values.

*:vector_bool*::
This field will hold a vector of C 'bool' values.

The integer types ':int32', ':uint32' ':int64', and ':uint64' are
implemented in the application as the corresponding types from
*stdint.h*, namely 'int32_t', 'uint32_t', 'int64_t', and 'uint64_t'
respectively.

The 'defMetric' command also recognizes the type ':long', which
corresponds to the C 'long' type. However, this type is deprecated
because 'long' changes size between 32-bit and 64-bit platforms. New
programs should use one of ':int32' or ':int64' instead.  See the *OML
TYPES* section of the linkoml:liboml2[3] man page for more information.

The types ':float' and ':real' are synonyms for the type ':double'.
In OML v2.5 and earlier, the types ':int' and ':integer' were synonyms
for ':long'.  Because ':long' is deprecated, these aliases are now
mapped to ':int32' from OML 2.6 and onwards.  To give developers a
chance to migrate their applications, we provide switches *--int32*
and *--long*.  Each one selects what the underlying type will be for
the ':int' and ':integer' aliases.  In OML 2.5, the default behaviour
if neither was specified was ':long', which could be overridden with
the --int32 switch.  In OML 2.6 and later the default is for ':int'
and ':integer' to map to ':int32', which developers can override using
the *--long* switch.

It is also permissible to use strings to specify the type of a metric,
i.e., '"int32"' instead of ':int32', '"double"' instead of ':double'.

BUT I DON'T KNOW RUBY!
----------------------

Although the template language uses Ruby syntax, you shouldn't need to
know Ruby in order to define applications using *oml2-scaffold*.  All
of the most useful features of the template language are illustrated
in the example above.  It should be sufficient to copy and paste the
example and then modify it to suit your own needs.  Two things are
worth mentioning about Ruby syntax:

1. Ruby strings can use either single quotes \'foo', double quotes
"bar", or any of several multi-line syntaxes.  The main difference
between the first two is in their behaviour when interpolating values
from Ruby variables, but this is not required for most purposes when
using *oml2-scaffold*.  The multi-line string syntaxes in Ruby are
even more esoteric; the one used above should be sufficient.

2. Ruby hash table literals are introduced using curly braces:
+
------
myhash = { 'a' => 1, 'b' => 2 }
------
+
This example constructs a hash in which the key \'a' maps to the value
1, and the key \'b' maps to the value 2.  Each key-value pair is
separated by a comma.
+
Ruby has a special rule for hashes that appear as arguments in a
method call:  you can omit the curly braces on a literal hash that
appears as the final argument in a method call.  This means that the
following two are equivalent:
+
-------
myobj1.foo(42, "hello", { 'a' => 1, 'b' => 2 })

myobj1.foo(42, "hello", 'a' => 1, 'b' => 2)
-------
+
The example application definition given above uses the second
syntax.  However, if one of the values of the hash is itself a hash,
then you have to include the curly braces on the value hash:
+
-------
myobj1.foo(42, "hello", 'a' => 1, 'b' => { :var_name => 'report_cpu' })
-------

If you do want to find out more about Ruby syntax, there are many good
tutorials on the Internet. This one is a good starting point:

--------
http://www.ruby-lang.org/en/documentation/quickstart/
--------

RESTRICTIONS ON NAMES
---------------------
The application name, the measurement point names ('defMeasurement'),
and the measurement point field names ('defMetric') should be
constrained to alpha-numeric names with a leading underscore or
letter.  This is because they can appear in the names of tables and
columns in the databases generated by the OML server, and therefore
both the client library and the server reject names that are not
easily used as SQL table and column names.

*oml2-scaffold* currently does not impose any restrictions on names,
but a future version probably will.

URI FORMAT
----------
The 'defApplication' command accepts a 'uri' parameter as documented
above.  The URI can be chosen according to user needs, and does not
have to start with \'omf:app' as in the example above.  When using the
*--app* option to generate a skeleton application definition,
*oml2-scaffold* will use the environment variable *USER* as the first
component of the uri, and \'app' as the second, so for a user named
bob, the following command line will result in an application with a
uri of \'bob:app:foo':
------
$ oml2-scaffold --app foo
------

FILES
-----
The *oml2-scaffold* program generates a single output file for each
possible command.  The files generated are named as follows:

--oml::
<app-name>_oml.h;;  The header defining the OML measurement points and helper
functions.

--opts::
<app-name>_popt.h;;  The header file defining the command line options
for linkman:popt[3]

--main::
<app-name>.c;;  The main C header file;
version.h;;     A file defining version information for the
application.

--make::
Makefile;;  A Makefile for building the program with *make*(1).

--app <app-name>::
<app-name>.rb;;  A skeleton application definition file.

NOTES
-----
This program used to be called 'oml2_scaffold' (with an underscore).
It was renamed to be more consistent with the other OML binaries,
which use the prefix 'oml2-' (with a hyphen).  The installation process
installs a link from 'oml2_scaffold' to 'oml2-scaffold' so as not to
break old scripts, but users should use the new name for new scripts,
and should try to migrate their old scripts to use the new name over
time.

BUGS
----
include::bugs.txt[]

SEE ALSO
--------
Manual Pages
~~~~~~~~~~~~
linkoml:oml2-server[1], linkoml:liboml2[1], linkoml:liboml2[3],
linkoml:liboml2.conf[5], linkoml:omlc_inject[3]

linkman:popt[3]

include::manual.txt[]

Ruby
~~~~
http://www.ruby-lang.org

// vim: ft=asciidoc:tw=72
