Skip to content

getappmap/appmap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 

Repository files navigation

AppMap data specification

The AppMap data specification is a JSON schema that contains detailed information of an application's runtime code execution, data snapshots and metadata. This data can be used to visualize and analyze code architecture, design, and behavior.

This repository serves as the home project for the AppMap data specification. For more information on the AppMap platform, visit appmap.io.

File structure

An AppMap file contains a single top level JSON object comprised of the following:

{
  "version": <string>,
  "metadata": <object>,
  "classMap": [ <tree of package, class, and function objects> ],
  "events": [ <list of event objects> ],
  "eventUpdates": <object>
}

version

Required version number to which the file conforms, such as: "1.4".

See the Changelog section for version history.

metadata

Optional information about the code from which the AppMap was extracted.

Metadata has the following attributes:

  • name Optional scenario name.
  • labels Optional list of arbitrary labels describing the AppMap.
  • app Optional name of the app to assign to the scenario. The organization to which the app belongs may be specified by separating the organization name and app name by a forward slash /. If no organization name is specified, the data is loaded into the user's personal data set. Example of a scoped name: myorg/myapp. Example of an unscoped name: myapp. The forward-slash character is illegal in app names and org names.
  • language Optional information about the programming language in which code is written.
    • name Required name of the programming language
    • engine Optional name of the programming langugae engine, e.g. VM variant.
    • version Required programming language version
  • frameworks Optional list of frameworks which the code uses.
    • name Required name of the framework.
    • version Required version of the framework.
  • client Required information about the AppLand client which recorded the scenario.
    • name Required short name of the client.
    • url Required unique URL of the client.
    • version Optional version of the client.
  • recorder Required information about the method which was used by the client to record the scenario.
    • type Required type of the recording method. Should be consistent across languages and clients. Options: code, process, requests, remote, tests.
    • name Required name of the recording method. This name must be unique to the client, but need not be unique across different clients.
  • recording Optional information about the entry-point function which was recorded.
    • defined_class Required name of the class which defines the entry-point function.
    • method_id Required name of the recorded function.
  • git Optional information about the state of the Git repo.
    • repository Required repository URL.
    • branch Required code branch.
    • commit Required commit identifier.
    • status Required status of the repo relative to the commit, represented as a list of status messages. If the repo is clean, the status should be an empty list.
    • user_name Optional Git user name.
    • user_email Optional Git email address.
    • tag Optional latest tag.
    • annotated_tag Optional latest annotated tag.
    • commits_since_tag Optional number of commits since the last tag.
    • commits_since_annotated_tag Optional number of commits since the last annotated tag.
  • source_location Optional path and line number of the source file that was recorded. Most commonly, this is the test case that was recorded. Format is <path>:<line>, with line being optional.
  • test_status Optional status of the test that ran to generate the AppMap. Valid values are succeeded or failed.
  • test_failure Optional details about a failed test.
    • message Required assertion failure message or exception message.
    • location Optional path and line number where the assertion failed or the exception was raised. Format is <path>:<line>, with line being optional.
  • exception Optional unhandled exception which occurred during scenairo processing.
    • class Required exception class name.
    • message Optional exception message.

Example

{
  "name": "Identity management in the UI permits login with a local password",
  "labels": [ "documentation" ],
  "app": "Discourse",
  "feature": "Login with valid locally managed credentials",
  "feature_group": "Authentication",
  "language": {
    "name": "ruby",
    "engine": "ruby",
    "version": "2.6.2"
  },
  "client": {
    "name": "appmap",
    "url": "https://github.com/applandinc/appmap-ruby",
    "version": "0.21.0"
  },
  "recorder": {
    "name": "rspec"
  },
  "test_status": "failed",
  "test_failure": {
      "message": "Expected true to be nil or false",
      "location": "spec/login_spec.rb:34"
  },
  "git": {
    "repository": "https://github.com/applandinc/appmap",
    "branch": "master",
    "commit": "c3424f9",
    "status": [
      "M spec/system/feature_spec.rb",
      "M spec/system/user_spec.rb"
    ],
    "annotated_tag": "v1.1.0",
    "commits_since_annotated_tag": "3"
  }
}

classMap

Required forest of code object trees, represented as a list of packages.

Code objects

There are three types of supported objects: package, class, and function. Note that the terms package and class are used loosely. In general, they encompass language-specific concepts such as "directory", "package", "class", "interface", "module", etc. Since an AppMap is a high-level representation of code, the detailed differences between these language-specific concepts aren't usually very important. Rules of thumb:

  • Use a package for each directory which contains code. A package may contain classes, but not functions.
  • Use a class for each type declaration in a code file. A class may contain functions and classes, but not packages.

Common attributes

Each classMap object has the following attributes:

  • name Required name. Should be the local name of the object, not the fully-scoped name. Example: "User" or "show", not "MyApp::User" or "User#show".
  • type Required object type. Must be "package", "class", or "function".

package and class attributes

Each "package" and "class" has the following attributes:

  • children Optional List of child objects which are semantically contained. Children of a package must be a class. Children of a class must be a class or function. Each class must be a descendant of a package.

function attributes

Each "function" has the following attributes:

  • location Recommended File path and line number, separated by a colon. Example: "/Users/alice/src/myapp/lib/myapp/main.rb:5".
  • static Required flag if the method is class-scoped (static) or instance-scoped. Must be true or false. Example: true.
  • labels Optional list of arbitrary labels describing the function.
  • comment Optional documentation comment for the function extracted from the source code.
  • source Optional verbatim source code of the function.

Note if recording several appmaps from the same code base comment and source can become widely redundant and contain duplicated data between the maps. For this reason it might be more convenient to omit them in specific AppMaps even if available, and instead create a separate AppMap with no events and just a classmap containing all code encountered in these recordings.

Example

[
  {
    "name": "appland",
    "type": "package",
    "children": [
      {
        "name": "AppLand",
        "type": "class",
        "children": [
          {
            "name": "Server",
            "type": "class",
            "children": [
              {
                "name": "API",
                "type": "class",
                "children": [
                  {
                    "name": "upload",
                    "location": "/src/architecture/lib/appland/server/api.rb:7",
                    "type": "function",
                    "static": false
                  }
                ]
              },
              {
                "name": "Model",
                "type": "class",
                "children": [
                  {
                    "name": "User",
                    "location": "/src/architecture/lib/appland/server/model.rb:5",
                    "type": "class",
                    "children": [
                      {
                        "name": "create",
                        "location": "/src/architecture/lib/appland/server/model.rb:6",
                        "type": "function",
                        "static": true
                      }
                    ]
                  },
                  {
                    "name": "Scenario",
                    "type": "class",
                    "children": [
                      {
                        "name": "create",
                        "location": "/src/architecture/lib/appland/server/model.rb:11",
                        "type": "function",
                        "static": true
                      },
                      {
                        "name": "review",
                        "location": "/src/architecture/lib/appland/server/model.rb:13",
                        "type": "function",
                        "static": false
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "name": "active_support",
    "type": "package",
    "children": [
      {
        "name": "ActiveSupport",
        "type": "class",
        "children": [
          {
            "name": "SecurityUtils",
            "type": "class",
            "children": [
              {
                "name": "secure_compare",
                "type": "function",
                "location": "/Users/ajp/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activesupport-6.0.3.2/lib/active_support/security_utils.rb:26",
                "static": true,
                "labels": [
                  "security"
                ]
              }
            ]
          }
        ]
      }
    ]
  }
]

events

Optional list of events which were recorded during program execution. Each object in this list is either a function call or a return from a function call which occurred during an actual program execution.

Common attributes

Each event object has the following attributes:

  • id Required unique identifier. Example: 23522.
  • event Required event type. Must be "call" or "return".
  • thread_id Required identifier of the execution thread. Example: 70340688724000.
  • timestamp Optional timestamp in seconds.

Common return attributes

Each "return" event has the following attributes:

  • parent_id Required id of the "call" event corresponding to this "return".
  • elapsed Optional elapsed time in seconds of this function call.

Function call attributes

A "call" event which represents a function call has the following attributes:

  • defined_class Required name of the class which defines the method. Example: "MyApp::User".
  • method_id Required name of the function which was called in this event. Example: "show".
  • path Recommended path name of the file which triggered the event. Example: "/src/architecture/lib/appland/local/client.rb".
  • lineno Recommended line number which triggered the event. Example: 5.
  • receiver Optional parameter object describing the object on which the function is called. Corresponds to the receiver, self and this concept found in various programming languages.
  • parameters Recommended array of parameter objects describing the function call parameters.
  • static Required flag if the method is class-scoped (static) or instance-scoped. Must be true or false. Example: true.

Note

In order to correlate function call events with function objects defined in the class map, the path and lineno attributes of each "call" event should exactly match the location attribute of the corresponding function in the classMap.

Parameter object format

Each parameter is an object containing the following attributes:

  • name Recommended name of the parameter. Example: "login".
  • object_id Recommended unique id of the object. Example: 70340693307040
  • class Required fully qualified class or type name of the object. Example: "MyApp::User".
  • value Required string describing the object. This is not a strict JSON serialization, but rather a display string which is intended for the user. These strings should be trimmed in length to 100 characters. Example: "MyApp user 'alice'"
  • size Recommended number of elements in an array or hash object. Example. "5".
  • properties Optional schema indicating property names and types of hash and hash-like objects. Each entry is a name, class and optional nested properties or items.
  • items Optional schema indicating element types of array and array-like objects. Each entry is a class and optional nested properties or items. Examples:
[
  {"name": "user_id", "class": "Integer"},
  {"name": "created_at", "class": "Date"},
  {"name": "followers", "class": "Array", "items": [{"class": "Integer" }]},
  {"name": "page", "class": "Hash", "properties": [
    { "name": "page_number", "class": "Numeric" },
    { "name": "offset", "class": "Numeric" },
    { "name": "total", "class": "Numeric" }
  ]
]

Exception object format

  • class Required fully qualified class name of the exception. Example: "com.myorg.InvalidUserException"
  • message Required description of the exception cause. Example: "User attribute not defined: 'email'"
  • object_id Required unique id of the object. Example: 70340693307040
  • path Optional path name of the file where the exception was thrown. Example: "/src/main/java/com/myorg/models/User.java".
  • lineno Optional line number where the exception was thrown. Example: 264.

Function return attributes

A "return" event which represents a function call has the following attributes:

  • return_value Optional object describing the return value. If present, this value uses parameter object format.
  • exceptions Optional array of exceptions causing this method to exit. If present, this value uses exception object format. When an exception is a wrapper for an underlying cause, the cause is the next exception in the exceptions array.

HTTP server request call attributes

A "call" event which represents an HTTP server request will have an http_server_request attribute, which is an object with the following elements:

  • request_method Required HTTP request method. Example: "POST".
  • path_info Required HTTP request path. Example: "/orders/84".
  • normalized_path_info Optional Parameterized request path. When present, each parameter must be formatted as {param-name}. Example: "/orders/{id}".
  • protocol Optional HTTP protocol and version. Example: "HTTP/1.1".
  • headers Recommended an object representing HTTP headers.

See: HTTP Request-Line

HTTP client request call attributes

A call event which represents an HTTP client request will have an http_client_request attribute, which is an object with the following elements:

  • request_method Required HTTP request method. Example: "POST".
  • url Required Request URL, excluding the query string. Example: "https://website.example/".
  • headers Recommended HTTP headers. Example: { "Content-Type": "application/json" }.

Any query parameters should be passed in the message attribute of the event.

HTTP server response return attributes

A return event which represents an HTTP server response will have an http_server_response attribute, which is an object with the following elements:

  • status_code Required HTTP status code
  • headers Recommended HTTP headers. Example: { "Content-Type": "application/json" }.
  • return_value Recommended for API routes, the object (e.g. JSON) returned by the method. It's recommended that this return_value have the optional properties (schema) field.

HTTP client response return attributes

A return event which represents an HTTP client response will have an http_client_response attribute, which is an object with the following elements:

  • status_code Required HTTP status code
  • headers Recommended an object representing HTTP headers of the response.
  • return_value Recommended for API routes, the object (e.g. JSON) returned by the method. It's recommended that this return_value have the optional properties (schema) field.

SQL query call attributes

A "call" event which represents a SQL query will have an sql_query attribute, which is an object with the following elements:

  • database_type Required name of the database. Example: "postgresql".
  • sql Required SQL query string.
  • explain_sql Optional query plan provided by the database engine.
  • server_version Optional database server version.

Message call attributes

A "call" event which represents the receipt of a message will have a message attribute, which is a list of objects in parameter object format. message is also used in http_client_request and http_server_request to indicate parameters.

Example

[
  {
    "id": 1,
    "event": "call",
    "defined_class": "AppLand::Local::Client",
    "method_id": "install",
    "path": "/src/architecture/lib/appland/local/client.rb",
    "lineno": 5,
    "static": true,
    "thread_id": 70340688724000,
    "receiver": {
      "name": "self"
      "class": "Module",
      "value": "AppLand::Local::Client",
      "object_id": 70340693307040
    },
    "parameters": [
      "name": "name"
      "class": "String",
      "value": "ruby",
      "object_id": 70340689027780
    ]
  },
  {
    "id": 2,
    "event": "return",
    "return_value": {
      "class": "Class",
      "value": "AppLand::Local::Client::Ruby",
      "object_id": 70340693343340
    },
    "parent_id": 1,
    "elapsed": 7.2e-05
  },
  {
    "id": 3,
    "event": "call",
    "defined_class": "AppLand::Local::UI::UI",
    "method_id": "initialize",
    "path": "/src/architecture/lib/appland/local/ui.rb",
    "lineno": 39,
    "static": false,
    "thread_id": 70340688724000,
    "receiver": {
      "name": "self"
      "class": "AppLand::Local::UI::UI",
      "value": "#<struct AppLand::Local::UI::UI visualizations=nil>",
      "object_id": 70340689072680
    },
    "parameters": [
      "name": "visualizations"
      "class": "Array",
      "value": "[AppLand::Local::UI::Component::Timeline, AppLand::Local::UI::Component::CallStack, AppLand::Local::",
      "object_id": 70340693502240
    ]
    }
  },
  {
    "id": 4,
    "event": "return",
    "return_value": {
      "class": "NilClass",
      "value": null,
      "object_id": 8
    },
    "parent_id": 3,
    "elapsed": 3.0e-06
  },
  {
    "id": 5,
    "event": "call",
    "defined_class": "AppLand::Local::Client",
    "method_id": "client",
    "path": "/src/architecture/lib/appland/local/client.rb",
    "lineno": 9,
    "static": true,
    "thread_id": 70340688724000,
    "receiver": {
      "name": "self"
      "class": "Module",
      "value": "AppLand::Local::Client",
      "object_id": 70340693307040
    },
    "parameters": []
  },
  {
    "id": 6,
    "event": "return",
    "exceptions": [
      {
        "class": "ClientValidationError",
        "message": "The client failed validation",
        "path": "/src/architecture/lib/appland/local/client.rb",
        "lineno": 8,
        "object_id": 70340693343340
      }
    ],
    "parent_id": 5,
    "elapsed": 2.0e-06
  }
]

eventUpdates

Optional Object containing events that were updated after they were added to the AppMap. The name of each attribute is the id of the updated event. The value of the attribute is an event object that should be used in place of the original event.

Example

{
  ...
  "events": [
    ...
    {
      "event": "call",
      "http_server_request": {
        "headers": {
          "host": "localhost:8080",
          "user-agent": "curl/7.79.1",
          "accept": "application/json"
        },
        "path_info": "/owners/1/pets/1/edit",
        "protocol": "HTTP/1.1",
        "request_method": "GET"
      },
      "id": 172,
      "thread_id": 182
    },
    ...
  ]
  ...
  "eventUpdates": {
    "172": {
      "event": "call",
      "http_server_request": {
        "headers": {
          "host": "localhost:8080",
          "user-agent": "curl/7.79.1",
          "accept": "application/json"
        },
        "normalized_path_info": "/owners/{ownerId}/pets/{petId}/edit",
        "path_info": "/owners/1/pets/1/edit",
        "protocol": "HTTP/1.1",
        "request_method": "GET"
      },
      "id": 172,
      "message": [
        {
          "class": "java.lang.String",
          "kind": "req",
          "name": "petId",
          "object_id": 836791441,
          "value": "1"
        },
        {
          "class": "java.lang.String",
          "kind": "req",
          "name": "ownerId",
          "object_id": 1966623949,
          "value": "1"
        }
      ],
      "thread_id": 182
    },
    ...
  ],
  ...
}

Validator

A schema validator is available:

appmap-js validator

Changelog

v1.13.1

  • Add code to metadata.recorder.type

v1.13.0

  • Add event.timestamp field.

v1.12.2

  • Clarify that classes can indeed contain classes, too, in the classmap.

v1.12.1

  • Clarify that classes can only contain functions in the classmap.

v1.12.0

  • Add metadata.test_failure to provide the failed test assertion and its location.

v1.11.0

  • Add items to parameter object format to describe array-like elements.

v1.10.0

  • Parameter object properties can be nested.

v1.9.0

  • Add metadata.recorder.type. Required for compliance with this version.

v1.8.0

  • Add eventUpdates.

v1.7.0

  • Add recommended size field to parameter object.
  • Add optional properties field to parameter object.
  • Add optional return_value to http_client_response and http_server_response.

v1.6.0

  • Add optional test_status and exception fields in metadata for conveying the test status.
  • Add HTTP request and response headers, as implemented by appmap-ruby.
  • Relax requirements on parameter objects.

v1.5.1

  • Specify format for parameters in normalized_path_info.

v1.5.0

  • Added http_client_request and http_client_response.

v1.4.1

  • Make source location optional; it's not always possible to provide it but appmaps lacking it can still be useful.
  • Make receiver and parameters optional; they not always make sense and there could be performance or operational reasons to skip capture.

v1.4.0

  • Added normalized_path_info to HTTP server request object.
  • Clarify required attributes for function call events, as compared to common attributes for all call events.

v1.3.0

  • Added comment and source to a function entry in the classmap.

v1.2.0

  • Added labels to a function entry in the classmap.
  • Moved static, defined_class, method_id, path, lineno from event common attributes to call-only events.
  • message changed from a map to an array of parameter objects.
  • Added labels, client, and recorder to metadata.
  • Removed layout, layout_owner and app_owner from metadata.

v1.1.0

  • parameters changed from a map to an array of parameter objects.
  • Added receiver, a parameter object.