NAME

oml2-scaffold - OML2 instrumentation code generator

SYNOPSIS

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 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 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 (oml_register_mps(3) and oml_inject_MPNAME(3)). The registration helper is only available when defining cpp(1) macro OML_FROM_MAIN prior to the #include statement for APPNAME_oml.h. This should only be done in the file calling oml_register_mps(3) (usually in the main() function).

--opts

Create the 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 popt(3) table and function to parse the options that they define.

The name parameter identifies the option.

The description parameter is used by 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 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 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 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 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 liboml2(1) and 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 omlc_guid_generate(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 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 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

If a problem you are experiencing is not addressed in the FAQ (http://oml.mytestbed.net/projects/oml/wiki/FAQ_and_Support) nor already present in the list of know bugs (http://oml.mytestbed.net/projects/oml/issues). You could discuss it on the mailing list (details and archives at http://oml.mytestbed.net/tab/show?id=oml).

It is however advisable to open a ticket on our issue tracker at http://oml.mytestbed.net/projects/oml/issues/new. Don’t forget to include details such as client and server logs (at [--oml-log-level|-d] 2). It also helps if you can share the source code of a (minimal, if possible) example reliably triggering the problem.