Skip to content

How to create analytics

jubustamantem edited this page Apr 21, 2023 · 8 revisions

How to create analytics

Introduction

It is quite helpful to keep track of several tools and plugins in UNCode. That is why we created the analytics plugin. This tool will tell UNCode superadmins some insights about it, for instance, Python tutor or custom input.

In this page you will find general information about how to add new diagram analytics to the plugin.

Plugins's general information

Location

The analytics plugin's code is located into the folder:

inginious/frontend/webapp/plugins/analytics

This tool is implemented as an UNCode plugin, this in order to have the module decoupled from the base code. The plugin adds a new in the superadmin menu on the right top, this is called analytics.

This opens a page that contains the several current plots and some filters. The different plots are organized by tabs. When the user clicks on every tab, it reloads the selected plot to bring the updated data.

Services

For this plug-in, we introduce a concept of service. A service is some that is being tracked. For example when a user uses custom input, or open Python Tutor, among other services that can be tracked. When that happens, a POST request is sent from Front-end. This request has some information like the name and key of service (we'll see more details about this later) and the course from which this service is being used.

The sent request will insert a document in the Database containing this information plus some automatically added additional data such date and username.

As per previous concept, UNCode currently tracks the following services:

  • Course admin statistics: When course administrator opens the course statistics, the request is sent.
  • Custom input: This is fired when user uses the custom input tool for multiple languages tasks.
  • Linter: keeps track when user clicks on button that triggers linter.
  • Python tutor: this is fired when user clicks on button 'Visualize code' to open Python tutor tool.
  • User statistics: when a student opens their statistics page.
  • Multiple languages - Code submission
  • Multiple languages - File submission
  • Data science - Code submission
  • Notebook submission
  • HDL - Code submission
  • Notebbok (External Grading) Submissions
  • Task editorial - Tutorial
  • Task editorial - Solution
  • Task hints - Unlocked by students

Database

Here are described the two collections that this plugin uses:

  • analytics: this collection stores all data from tracked services. Here is an example of document:

    {
        "_id": "ObjectId('5eda87ca58929ce8fe7ac360')",
        "date": "ISODate('2020-06-05T12:58:34.863Z')",
        "username": "user",
        "service": "admin_statistics",
        "session_id": "0335405e8924928995f59c028505a180cf059596",
        "course_id": "pc-group18_2020_1"
    }
  • services : this collection stores all tracked services. This is used to make easy the process to add new services to track and to know all different services. Here is an example of a store document:

    {
        "_id": "ObjectId('5eda87ca58929ce8fe7ac361')",
        "service_name": "Course admin statistics",
        "service_key": "admin_statistics"
    }

    For that, a key and name are necessary. This data is sent from the generated request as we will see below.

Add new services

As explained before, a visit to a service is generate by a POST request to the endpoint /api/analytics/. For that, this request must be sent from UNCode Front-end, more specifically, using JavaScript.

Here is and example of how this request is done to send visits from User statistics (inginious/frontend/plugins/statistcs/pages/user_statistics.html):

$.post('/api/analytics/', {
    service: {
        key: "user_statistics",
        name: "User statistics"
    },
    course_id: getCourseId(),
});

In general the request payload most be the next Json object:

{
    "service": {
        "key": "service_key",
        "name": "Service name"
    },
    "course_id": "Course ID"
}
  • The service key will be the identifier for that service.
  • Service name is the name for that service that will be displayed in analytics page.
  • course_id to know where the analytics are sent from. In case the service is not associated to a course, set this empty.

When the request is sent for the first time with the new service, the services collection is updated with this new service only once. After that, every triggered request will insert a new document in analytics collection with the corresponding data.

Add more plots

This process involve two main steps:

  1. Create an API that generates the information that will be showed to the user.
  2. Consume the API from a web page and visualize the information.
  • Create API:

    Analytics APIs are implemented as UNCode pages in the pages.py file (inside the plug-in folder). These APIs inherit from SuperadminAPI to allow only request from superadmin users. In the folder *inginious/frontend/plugins/analytics/api/ *are located the current implemented APIs.

    If your class inherit from SuperadminAPI, you must override the API_GET method. The method has to return a tuple with the HTTP code state (generally 200) and the response object (that is transformable to JSON). In general, the APIs have to generate a query to the Data Base (MongoDB). That way, the returned data is reduced and almost processed for the plot. This reduces the response payload, making the rendering much faster.

    Note: in the SuperadminAPI class, you can validate the superadmin permissions when the API_GET method is executed. Therefore, it is mandatory to call this method inside API_GET method or in other case users without superadmin permissions could use the API. For that set the next line:

    self.check_superadmin_rights()

    When the API is ready, you can add the endpoint so the requests are sent. For that add the next line in the init.py file, setting correctly the endpoint name and the class to run when that api is called.

    plugin_manager.add_page('/api/api_name/', ApiNameAPI)

    Additionally, the next files classes and files you can find:

    • analytics_collection_manager.py: Implements a singleton class AnalyticsCollectionManagerSingleton, that works as in interface between the analytics collection and UNCode. Provides some methods to manage this collection.
    • services_collection_manager.py: Implements a singleton class ServicesCollectionManagerSingleton, that works as in interface between the services collection and UNCode. Provides some methods to manage this collection.
    • utils: some utilities for the plug-in.
  • Visualize the information:

    This visualization is done with JavaScript, mainly using plotly library. Bellow are described the main files:

    • pages/analytics.html: HTML template for analytics page.
    • static/js/analytics.js: script with common code for all analytics plots.
    • static/js/<plot_name>.js: js scripts containing the logic for the specific plot.

    Adding a new plot to visualize it can be done following next steps:

    1. Create a new tab into the analytics template.
    2. Create a class and its prototype as AnalyticsDiagram (Defined in analytics.js file) creating a new script for that new plot. In overall, have to override _plotData method (in charge to "draw" the information). Check the current script to have a guide on this.
    3. Ensure you are calling plot() method in the new plot when the new tab is opened.
    4. Update the Minify plugins utility with the new added files in the analytics part that generates the min files. This is to update correctly the .min files with this new script. See the Minify static files documentation to see how to update this.
Clone this wiki locally