Skip to content

Latest commit

 

History

History
835 lines (737 loc) · 24.5 KB

telemetry-v3.md

File metadata and controls

835 lines (737 loc) · 24.5 KB

Telemetry Envelope

{
  // About the event
  "eid": , // Required.
  "ets": , // Required. Epoch timestamp of event (time in milli-seconds. For ex: 1442816723)
  "ver": , // Required. Version of the event data structure, currently "3.0"
  "mid": , // Required. Unique message ID. Used for deduplication, replay and update indexes

  // Who did the event
  "actor": { // Required. Actor of the event.
    "id": , // Required. Can be blank. Id of the actor. For ex: uid incase of an user
    "type":  // Required. Can be blank. User, System etc.
  },

  // Context of the event
  "context": { // Required. Context in which the event has occured.
    "channel": , // Required. Channel which has produced the event
    "pdata": { // Optional. Producer of the event
      "id": , // Required. unique id assigned to that component
      "pid": , // Optional. In case the component is distributed, then which instance of that component
      "ver":  // Optional. version number of the build
    },
    "env": , // Required. Unique environment where the event has occured.
    "sid": , // Optional. session id of the requestor stamped by portal
    "did": , // Optional. uuid of the device, created during app installation
    "cdata": [{ // Optional. correlation data
      "type":"", // Required. Used to indicate action that is being correlated
      "id": "" // Required. The correlation ID value
    }],
    "rollup": { // Optional. Context rollups example: Organization heirarchy("L1": "Parent org id", "l2": "sub org id")
      "l1": "",
      "l2": "",
      "l3": "",
      "l4": ""
    }
  },

  // What is the target of the event
  "object": { // Optional. Object which is the subject of the event.
    "id": , // Required. Id of the object. For ex: content id incase of content
    "type": , // Required. Type of the object. For ex: "Content", "Community", "User" etc.
    "ver": , // Optional. version of the object
    "rollup": { // Optional. Rollups to be computed of the object. Only 4 levels are allowed. example: Textbook heirarchy("L1": "Parent node id", "l2": "Child node id")
      "l1": "",
      "l2": "",
      "l3": "",
      "l4": ""
    }
  },

  // What is the event data
  "edata": {} // Required.

  // Tags
  "tags": [""] // Optional. Encrypted dimension tags passed by respective channels
}

Telemetry Events

  • START - Start of a multi step activity. For ex: Session, App, Tools, Community etc would have start and end
  • END - End of a work flow
  • IMPRESSION - A visit to a specific page by an user
  • INTERACT - User interaction on the page (such as search, click, preview, move, resize, configure)
  • ASSESS - An assessment has happened during content play
  • RESPONSE - To capture an user response. For ex: Responded to a poll or a calendar event or a question
  • INTERRUPT - An interrupt trigged to the app (such as mobile app sent to background)
  • FEEDBACK - Feedback provided
  • SHARE - When any share happens. For ex: Share content, telemetry data, link, file etc
  • AUDIT - When an object is changed. This includes lifecycle changes as well.
  • ERROR - When an error has occured
  • HEARTBEAT - An heart beat event to denote that the process is running.
  • LOG - Generic log event. API call, Service call, app update etc
  • SEARCH - A search is triggered (content, item, asset etc)
  • METRICS - Service business metrics (also accessible via health API)
  • SUMMARY - A summary event
  • EXDATA - A generic wrapper event to capture encrypted/serialized data

Standard Flow

Mobile App Standard Flow

Here is the standard flow of events in the stack for a mobile application:

START(type: "app")
    ...| --> app events such as IMPRESSION, FEEDBACK, etc may happen
    START(type: "session")
        ...
        | --> IMPRESSION - For the pages that the user visits
        | --> INTERACT --> one of the content is clicked
            | --> START(type: "player") --> events generated by specific content
                ...|
                ...| --> in-content events such as ASSESS, INTERACT, IMPRESSION, LEVEL_SET etc.
                ...|
            | --> END(type: "player")
        | --> IMPRESSION - Returned back to mobile app for content player
        ...| --> app events such as IMPRESSION, INTERACT, etc. may happen
        | --> INTERACT --> one of the content is clicked
            | --> START(type: "player") --> events generated by specific content
                ...|
                ...| --> in-content events such as ASSESS, INTERACT, IMPRESSION, LEVEL_SET etc.
                ...|
            | --> END(type: "player")
        | --> IMPRESSION - Returned back to mobile app for content player
        ...| --> app events such as IMPRESSION, INTERACT, etc. may happen
    END(type: "session")
    ...| --> app events such as APP_UPDATE, FEEDBACK, etc may happen
END(type: "app")

Portal Standard Flow

Here is the standard flow of events in the portal stack:

AUDIT (object: user) --> (Optional if a user is created for the first time)
START(type: "session") --> User session starts
    ...
    | --> IMPRESSION - For the pages that the user visits
    | --> INTERACT - For the interactions on the page
    // there is no explicit logout/timeout

Editor Standard Flow

Sample flow to find out when assets are added or removed

START (type: "session") - User logs in
    ...
    | --> IMPRESSION (Portal) - User visits content creation page (cdata session)
    | --> INTERACT (Portal) - User initiates content creation
    | --> AUDIT (Platform) - User creates a new content
    | --> START (type: "editor", mode: "content")
        ...
        | --> INTERACT (Editor) - In editor, user is loading the asset browser
        | --> SEARCH (Platform) - In AT, user is searching for assets (cdata session, search result id)
        | --> PLUGIN_LIFECYCLE (Editor) - User selects the asset for content (which search result was used)
        | --> PLUGIN_LIFECYCLE (Editor) - User removes the asset from content
        | --> INTERACT (Editor) - User clicks save in AT
        | --> ACCESS (Platform) - Platform save API is called
        | --> INTERACT (Editor) - User clicks on submit to review
        | --> AUDIT (object: Content, state: "Review", prevstate: "Draft") - Platform sends the content to review state
    | --> END (type: "editor", mode: "content") - User closes the editor and goes back to portal

Back-end Services Standard Flow

AUDIT (object: Service, state: "Ready") --> State transition to READY
    ...| --> ACCESS events for API requests
    ACCESS
        LOG --> Log events in the context of the incoming request (by request correlation ID)
        ...
    METRICS --> Health/business metrics (e.g. number of jobs executed)
AUDIT (object: Service, state: "Stopped") --> State transition to STOPPED

Analytics Jobs Standard Flow

Here is the standard flow of events in the analytics job stack:

JOB_START --> Data product job start
    ...
    | --> JOB_LOG - To log some data while Data product job is in progress
    ...
JOB_END --> Data product job end

Event Definitions

Following sections provide exact event specific structures edata for all events. Generic envelope is defined here.

Defined Structures

// Device Specification
DSPEC = {
  "os": "", // OS name and version
  "make": "", // device make and model
  "id": "", // physical device id if available from OS
  "mem": , // total mem in MB, -1 if unknown
  "idisk": , // total internal disk in GB, -1 if unknown
  "edisk": , // total external disk (card) in GB, -1 if unknown
  "scrn": , // screen size in inches, -1 if unknown
  "camera": "13,1.3", // primary and secondary camera specs
  "cpu": "", // processor name
  "sims" , // number of sim cards, -1 if unknown
  "cap": []
}

UASPEC = {
  "agent": "Mozilla", // which user agent (mozilla, chrome, safari, ie)
  "ver": "5.0", // Agent version number
  "system": "iPad; U; CPU OS 3_2_1 like Mac OS X; en-us" // System identification
  "platform": "AppleWebKit/531.21.10" // client platform,
  "raw": "Mozilla\/5.0 (X11; Linux x86_64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.98 Safari\/537.36" // Raw user agent of server  
}

OBJECT = {
  "id": "", // Required. unique id for the object type
  "type": "", // Required. Object Type - Tag, User, Partner, Content, Item, Asset
  "ver": "", // Required. Version of the object
  "subtype": "", // Optional. Sub type for each respective type. For ex: for Content - Story/Worksheet/Resource etc.
  "name": "", // Optional. Name of the object eg: Name of the partner or user or content
  "code": "", // Optional. unique code for the object
  "parent": {
    "id": "", // Optional. parent id of the object
    "type": "" // Optional. parent type of the object. Required if parentid is present.
  }
}

TARGET = {
  "id": "", // Required. unique id for the target
  "ver": "", // Required. version of the target
  "type": "", // Required. Type of the target
  "parent": {
    "id": "", // Optional. parent id of the object
    "type": "" // Optional. parent type of the object. Required if parentid is present.
  }
}

PLUGIN = {
  "id": "", // Required. unique id for the plugin. For ex: org.ekstep.text
  "ver": "", // Required. version of the plugin
  "category": "" // Optional. Category of the plugin. For ex: "core", "library", "numeracy" etc
}

VISIT = {
  "objid": "", // Required. unique id for the object visited
  "objtype": "", // Required. Type of the object visited
  "objver": "", // Optional. version of the object visited
  "section": "", // Optional. Free flowing text
  "index": // Optional. Index of the object within a given list
}

QUESTION = {
  "id": "", // unique assessment question id. its an required property.
  "type": "", // type of the question. its an optional property.
  "maxscore", // user defined score to this assessment/question.
  "exlength": , // expected time (decimal number) in seconds that ideally child should take
  "params": [ // Array of parameter tuples
     {"id":"value"} // for ex: if var1 is substituted with 5 apples the parameter is {"var1":"5"}
  ],
  "uri": "", // Unique external resource identifier if any (for recorded voice, image, etc.)
  "desc": "short description",
  "title": "title",
  "mmc": [], // User defined missing micros concepts
  "mc": []   // micro concepts list
}

START

{
  "edata": {
    "type": "", // Required. app, session, editor, player, workflow, assessment
    "dspec": DSPEC, // Optional. Device spec
    "uaspec": UASPEC, // Optional. User agent spec
    "loc": "", // Optional. Location of the device
    "mode": "", // Optional. Mode of start. For "player" it would be "play/edit/preview". For Workflow it would be Review/Flag/Publish. For editor it could be "content", "textbook", "generic", "lessonplan" etc
    "duration": , // Optional. Time taken to initialize/start
    "pageid": "" // Optional. Page/Stage id where the start has happened.
  }
}

END

{
  "edata": {
    "type": , // Required. app, session, editor, player, workflow, assessment
    "mode": "", // Optional. Mode of start. For "player" it would be "play/edit/preview". For Workflow it would be Review/Flag/Publish. For editor it could be "content", "textbook", "generic", "lessonplan" etc
    "duration": , // Optional. Total duration from start to end in seconds
    "pageid": "", // Optional. Page/Stage id where the end has happened.
    "summary": [{"key":"value"}] // Optional. Summary of the actions done between start and end. For ex: "progress" for player session, "nodesModified" for collection editor
  }
}

IMPRESSION

{
  "edata": {
    "type": "", // Required. Impression type (list, detail, view, edit, workflow, search)
    "subtype": "", // Optional. Additional subtype. "Paginate", "Scroll"
    "pageid": "", // Required. Unique page id
    "uri": "", // Required. Relative URL of the content
    "duration": , // Optional. Time taken to render the page/stage in seconds
    "visits": [VISIT] // Optional. Capture the object visits
  }
}

INTERACT

{
  "edata": {
    "type": "", // Required. Type of interaction CLICK,TOUCH,DRAG,DROP,PINCH,ZOOM,SHAKE,ROTATE,SPEAK,LISTEN,WRITE,DRAW,START,END,CHOOSE,ACTIVATE,SHOW,HIDE,SCROLL,HEARTBEAT,OTHER
    "subtype": "", // Optional. Additional types for a global type. For ex: for an audio the type is LISTEN and thesubtype can be one of PLAY,PAUSE,STOP,RESUME,END
    "id": "", // Required. Resource (button, screen, page, etc) id on which the interaction happened - use systemidentifiers when reporting device events
    "pageid": "", // Optional. Stage or page id on which the event happened
    "target": TARGET, // Optional. Target context where the interaction has happened
    "duration": , // Optional. Time taken to interact on object in seconds
    "plugin": PLUGIN, // Optional. Plugin on which the interaction has happend
    "extra": { // Optional. Extra attributes for an interaction
      "pos": [{"x":,"y":,"z":}], // Array of positional attributes. For ex: Drag and Drop has two positional attributes. One where the drag has started and the drop point
      "values": [], // Array of values, e.g. for timestamp of audio interactions
    }
  }
}

ASSESS

{
  "edata": {
    "item": QUESTION, // Required. Question Data
    "index": , // Optional. Index of the question within a content.
    "pass": "", // Required. Yes, No. This is case-sensitive. default value: No.
    "score": , // Required. Evaluated score (Integer or decimal) on answer(between 0 to 1), default is 1 if pass=YES or 0 if pass=NO. 
    "resvalues": [{"id":"value"}], // Required. Array of key-value pairs that represent child answer (result of this assessment)
    "duration":  // Required. time taken (decimal number) for this assessment in seconds
  }
}

RESPONSE

{
  "edata": {
    "target": TARGET, // Required. Target of the response
    "type": "", // Required. Type of response. CHOOSE, DRAG, SELECT, MATCH, INPUT, SPEAK, WRITE
    "values": [{"key":"value"}] // Required. Array of response tuples. For ex: if lhs option1 is matched with rhs optionN - [{"lhs":"option1"}, {"rhs":"optionN"}]
  }
}  

Examples

  1. Responding to a question
{
  "object": {
    "id": "content101",
    "type": "content",
    "hrchy": {
      "l1": "textbook101",
      "l2": "course101",
      "l3": "curriculumA"
    }
  }
  "edata": {
    "target": {
      "id": "q-101",
      "type": "AssessmentItem",
      "parent": {

      }
    }, // Required. Question Data
    "type": "SELECT", // Required. Type of response. CHOOSE, DRAG, SELECT, MATCH, INPUT, SPEAK, WRITE
    "values": [{"state":"selected", "option": "A"}] // Required. Array of response tuples. For ex: if lhs option1 is matched with rhs optionN - [{"lhs":"option1"}, {"rhs":"optionN"}]
  }
}
  1. Responding to a poll
{
  "object": {
    "id": "community101",
    "type": "Community",
    "hrchy": {
      "l1": "poll101",
      "l2": "thread202",
      "l3": "forum211"
    }
  }
  "edata": {
    "target": {
      "id": "p101",
      "type": "Poll",
      "parent": {
        "id": "thread202",
        "type": "ForumThread"
      }
    }, // Required. Question Data
    "type": "MATCH", // Required. Type of response. CHOOSE, DRAG, SELECT, MATCH, INPUT, SPEAK, WRITE
    "values": [{"state":"selected", "option": "A"}] // Required. Array of response tuples. For ex: if lhs option1 is matched with rhs optionN - [{"lhs":"option1"}, {"rhs":"optionN"}]
  }
}
  1. Responding to a calendar event (rsvp)
{
  "object": {
    "id": "community101",
    "type": "Community"
    "hrchy": {
      "l1": "cal101"
    }
  },
  "edata": {
    "target": {
      "id": "event101",
      "type": "Event",
      "parent": {
        "id": "cal101",
        "type": "Calendar"
      }
    }, // Required. Question Data
    "type": "CHOOSE", // Required. Type of response. CHOOSE, DRAG, SELECT, MATCH, INPUT, SPEAK, WRITE
    "values": [{"state": "selected", "option":"Rejected/Decline", "reason": "Conflicting schedule"}] // Required. Array of response tuples. For ex: if lhs option1 is matched with rhs optionN - [{"lhs":"option1"}, {"rhs":"optionN"}]
  }
}

INTERRUPT

{
  "edata": {
    "type": "", // Required. [m:background, m:resume]
    "pageid": "" // Optional. Page id where the interrupt has happened
  }
}

FEEDBACK

{
  "edata": {
    "rating": 3, // Optional. Numeric score (+1 for like, -1 for dislike, or 4.5 stars given in a rating)
    "comments": "User entered feedback" // Optional. Text feedback (if any)
  }
}

SHARE

{
  "edata": {
    "dir": "", // In/Out
    "type": "", // File/Link/Message
    "items": [{ // Required. array of items shared
      "id": "",
      "type": "",
      "ver": ""
      "params": [
        {"key": "value"}
      }],
      "origin": { // Origin of the share file/link/content
        "id": "", // Origin id
        "type": "" // Origin type
      },
      "to": {
        "id": "",
        "type": ""
      }
    }]
  }
}  

Examples

  1. Export content on app
{
  "edata": {
    "dir": "out", 
    "type": "File",
    "items": [{
      "id": "numeracy_377",
      "type": "Content",
      "ver": "11",
      "params": [
        {"transfers": "3"},
        {"size": "23456.0"}
      ],
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }, {
      "id": "numeracy_398",
      "type": "Content",
      "ver": "5",
      "params": [
        {"transfers": "7"},
        {"size": "23456.0"}
      ],
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }]
  }
}
  1. Import content on app
{
  "edata": {
    "dir": "in", 
    "type": "File",
    "items": [{
      "id": "numeracy_377",
      "type": "Content",
      "ver": "11",
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }, {
      "id": "numeracy_398",
      "type": "Content",
      "ver": "5",
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }]
  }
}
  1. Download content on app
{
  "edata": {
    "dir": "in",
    "type": "File",
    "items": [{
      "id": "numeracy_377",
      "type": "Content",
      "ver": "11"
    }]
  }
}
  1. Export profile on app
{
  "edata": {
    "dir": "out",
    "type": "File",
    "items": [{
      "id": "user1",
      "type": "User",
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }, {
      "id": "user999",
      "type": "User",
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }]
  }
}
  1. Import profile on app
{
  "edata": {
    "dir": "in",
    "type": "File",
    "items": [{
      "id": "user1",
      "type": "User",
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }, {
      "id": "user999",
      "type": "User",
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }]
  }
}
  1. Export telemetry on app
{
  "edata": {
    "dir": "out",
    "type": "File",
    "items": [{
      "id": "telemetry1",
      "type": "Telemetry",
      "params": [
        {"count": "70"},
        {"size": "23456.0"}
      ],
      "origin": {
        "id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
        "type": "Device"
      }
    }]
  }
}
  1. Share link
{
  "edata": {
    "dir": "in",
    "type": "Link",
    "items": [{
      "obj": {
        "id": "numeracy_377",
        "type": "Content"
      },
      "params": [
        {"link": "https://community.ekstep.in/content/numeracy_377"}
      ]
    }]
  }
}
  1. Share Post
{
  "edata": {
    "dir": "out",
    "type": "Message",
    "items": [{
      "obj": {
        "id": "thread101",
        "type": "ForumThread"
      },
      "to": {
        "id": "comm202",
        "type": "Community"
      }
    }]
  }
}

AUDIT

{
  "edata": {
    "props": [""], // Updated properties
    "state": "", // Optional. Current state
    "prevstate": "", // Optional. Previous state
    "duration":  // Optional. Duration or time taken in seconds to change from prevstate to current state. Should only be passed if the state has truly changed
  }
}

ERROR

{
  "edata": {
    "err": "", // Required. Error code
    "errtype": "", // Required. Error type classification - "SYSTEM", "MOBILEAPP", "CONTENT"
    "stacktrace": "", // Required. Detailed error data/stack trace
    "pageid": "", // Optional. Page where the error has occured
    "object": OBJECT, // Optional. Object on which the error occured
    "plugin": PLUGIN // Optional. Plugin in which the error occured
  }
}

HEARTBEAT

{
  "edata": {
  }
}

LOG

{
  "edata": {
    "type": "", // Required. Type of log (system, process, api_access, api_call, job, app_update etc)
    "level": "", // Required. Level of the log. TRACE, DEBUG, INFO, WARN, ERROR, FATAL
    "message": "", // Required. Log message
    "pageid": "", // Optional. Page where the log event has happened
    "params": [{"key":"value"}] // Optional. Additional params in the log message
  }
}  

Exaples

  1. Simple log
  1. API log when being accessed
{
  "edata": {
    "type": "api_access",
    "level": "INFO",
    "message": "",
    "params": [
      {"rid": "org.ekstep.search"}, // Resource being accessed
      {"uip": "10.0.0.7"}, // User IP address (if available) - server will anonymize
      {"title": "Search API"}, // Title of the resource for analytics (e.g. the page title)
      {"category": "contentsearch"}, // Categorization of the event
      {"url": "/content/search"}, // Categorization of the event
      {"size": "3333"}, // Size of the response in bytes
      {"duration": "333"}, // Response time in ms
      {"status": "200"}, // Response code (use standard protocol codes - e.g. 200, 404)
      {"protocol": "http"}, // Protocol of access (http, or others such as messaging/Akka calls)
      {"method": "GET"}, // Protocol specific method (e.g. GET/POST)
      {"req": ""} // Serialized request
    ]
  }
}

SEARCH

Please note:

  1. The search is not indexed as it might contain PII
  2. The search is available as an exhaust post anonymization
{
  "edata": {
    "type": "",
    "query": "", // Required. Search query string 
    "filters": {}, // Optional. Additional filters (see the API spec)
    "sort": {}, // Optional. Additional sort parameters
    "correlationid": "", // Optional. Server generated correlation id (for mobile app's telemetry)
    "size": 333, // Required. Number of search results
    "topn": [{}] // Required. top N (configurable) results with their score
  }
}

METRICS

{
  "edata": {
    "metric1": Int,
    "metric2": Int
    /// more metrics, each is a key value
  }
}

SUMMARY

{
  "edata": {
    "type": "", // Required. Type of summary. Free text. "session", "app", "tool" etc
    "mode": "", // Optional.
    "starttime": Long, // Required. Epoch Timestamp of app start. Retrieved from first event.
    "endtime": Long, // Required. Epoch Timestamp of app end. Retrieved from last event.
    "timespent": Double, // Required. Total time spent by visitor on app in seconds excluding idle time.
    "pageviews": Long, // Required. Total page views per session(count of CP_IMPRESSION)
    "interactions": Long, // Required. Count of interact events
    "envsummary": [{ // Optional
        "env": String, // High level env within the app (content, domain, resources, community)
        "timespent": Double, // Time spent per env
        "visits": Long // count of times the environment has been visited
    }],
    "eventssummary": [{ // Optional
        "id": String, // event id such as CE_START, CE_END, CP_INTERACT etc.
        "count": Long // Count of events.
    }],
    "pagesummary": [{ // Optional
        "id": String, // Page id
        "type": String, // type of page - view/edit
        "env": String, // env of page
        "timespent": Double, // Time taken per page
        "visits": Long // Number of times each page was visited
    }]
  }
}

EXDATA

{
  "edata": {
    "type": "", // Free flowing text. For ex: partnerdata, xapi etc
    "data": "" // Serialized data (can be either encrypted/encoded/stringified)
  }
}