-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Feature/#174 add mongodb support
- Loading branch information
Showing
15 changed files
with
641 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
Type: Package | ||
Package: shiny.telemetry | ||
Title: 'Shiny' App Usage Telemetry | ||
Version: 0.2.0.9012 | ||
Version: 0.2.0.9013 | ||
Authors@R: c( | ||
person("André", "Veríssimo", , "[email protected]", role = c("aut", "cre")), | ||
person("Kamil", "Żyła", , "[email protected]", role = "aut"), | ||
person("Krystian", "Igras", , "[email protected]", role = "aut"), | ||
person("Recle", "Vibal", , "[email protected]", role = "aut"), | ||
person("Arun", "Kodati", , "[email protected]", role = "aut"), | ||
person("Wahaduzzaman", "Khan", , "[email protected]", role = "aut"), | ||
person("Appsilon Sp. z o.o.", , , "[email protected]", role = "cph") | ||
) | ||
Description: Enables instrumentation of 'Shiny' apps for tracking user | ||
|
@@ -48,6 +49,7 @@ Suggests: | |
RMariaDB, | ||
RPostgreSQL, | ||
RPostgres, | ||
mongolite, | ||
scales, | ||
semantic.dashboard (>= 0.1.1), | ||
shiny.semantic (>= 0.2.0), | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
#' Data storage class with MongoDB provider | ||
#' | ||
#' @description | ||
#' Implementation of the [`DataStorage`] R6 class to MongoDB backend using a | ||
#' unified API for read/write operations | ||
#' | ||
#' @export | ||
#' | ||
#' @examples | ||
#' \dontrun{ | ||
#' data_storage <- DataStorageMongoDB$new( | ||
#' host = "localhost", | ||
#' db = "test", | ||
#' ssl_options = mongolite::ssl_options() | ||
#' ) | ||
#' data_storage$insert("example", "test_event", "session1") | ||
#' data_storage$insert("example", "input", "s1", list(id = "id1")) | ||
#' data_storage$insert("example", "input", "s1", list(id = "id2", value = 32)) | ||
#' | ||
#' data_storage$insert( | ||
#' "example", "test_event_3_days_ago", "session1", | ||
#' time = lubridate::as_datetime(lubridate::today() - 3) | ||
#' ) | ||
#' | ||
#' data_storage$read_event_data() | ||
#' data_storage$read_event_data(Sys.Date() - 1, Sys.Date() + 1) | ||
#' data_storage$close() | ||
#' } | ||
DataStorageMongoDB <- R6::R6Class( # nolint object_name. | ||
classname = "DataStorageMongoDB", | ||
inherit = DataStorage, | ||
# | ||
# Public | ||
public = list( | ||
|
||
#' @description | ||
#' Initialize the data storage class | ||
#' @param hostname the hostname or IP address of the MongoDB server. | ||
#' @param port the port number of the MongoDB server (default is 27017). | ||
#' @param username the username for authentication (optional). | ||
#' @param password the password for authentication (optional). | ||
#' @param authdb the default authentication database (optional). | ||
#' @param dbname name of database (default is "shiny_telemetry"). | ||
#' @param options Additional connection options in a named list format | ||
#' (e.g., list(ssl = "true", replicaSet = "myreplicaset")) (optional). | ||
#' @param ssl_options additional connection options such as SSL keys/certs | ||
#' (default is [`mongolite::ssl_options()`]). | ||
|
||
initialize = function( | ||
hostname = "localhost", | ||
port = 27017, | ||
username = NULL, | ||
password = NULL, | ||
authdb = NULL, | ||
dbname = "shiny_telemetry", | ||
options = NULL, | ||
ssl_options = mongolite::ssl_options() | ||
) { | ||
# create the connection string for mongodb | ||
checkmate::assert_string(hostname) | ||
checkmate::assert_int(port) | ||
checkmate::assert_string(username, null.ok = TRUE) | ||
checkmate::assert_string(password, null.ok = TRUE) | ||
checkmate::assert_string(authdb, null.ok = TRUE) | ||
checkmate::assert_string(dbname) | ||
checkmate::assert_list(options, null.ok = TRUE) | ||
checkmate::assert_list(ssl_options, null.ok = TRUE) | ||
|
||
password_debug <- if (is.null(password)) { | ||
"(empty)" | ||
} else { | ||
digest::digest(password, algo = "sha256") | ||
} | ||
|
||
logger::log_debug( | ||
"Parameters for MongoDB:\n", | ||
" * username: {username %||% \"(empty)\"}\n", | ||
" * password (sha256): {password_debug}\n", | ||
" * hostname:port: {hostname}:{port}\n", | ||
" * db name: {dbname}\n", | ||
" * authdb: {authdb %||% \"(empty)\"}\n", | ||
" * options: {jsonlite::toJSON(options, auto_unbox = TRUE)}\n", | ||
" * ssl_options: ", | ||
"{jsonlite::toJSON(unclass(mongolite::ssl_options()), auto_unbox = TRUE)}\n", | ||
namespace = "shiny.telemetry" | ||
) | ||
|
||
private$connect( | ||
url = build_mongo_connection_string( | ||
hostname = hostname, | ||
port = port, | ||
username = username, | ||
password = password, | ||
authdb = authdb, | ||
options = options | ||
), | ||
dbname, | ||
options = ssl_options | ||
) | ||
} | ||
), | ||
# | ||
# Private | ||
private = list( | ||
# Private Fields | ||
db_con = NULL, | ||
|
||
# Private methods | ||
connect = function(url, dbname, options) { | ||
# Initialize connection with database | ||
private$db_con <- mongolite::mongo( | ||
url = url, | ||
db = dbname, | ||
collection = self$event_bucket, | ||
options = options | ||
) | ||
}, | ||
|
||
close_connection = function() { | ||
private$db_con$disconnect() | ||
}, | ||
|
||
write = function(values, bucket) { | ||
checkmate::assert_choice(bucket, choices = c(self$event_bucket)) | ||
checkmate::assert_list(values) | ||
|
||
if (!is.null(values$details)) { | ||
values$details <- jsonlite::fromJSON(values$details) | ||
} | ||
|
||
private$db_con$insert(values, auto_unbox = TRUE, POSIXt = "epoch") | ||
}, | ||
|
||
read_data = function(date_from, date_to, bucket) { | ||
checkmate::assert_choice(bucket, c(self$event_bucket)) | ||
|
||
event_data <- private$db_con$find( | ||
query = build_query_mongodb(date_from, date_to), | ||
fields = '{"_id": false}' | ||
) | ||
|
||
if (nrow(event_data) > 0) { | ||
result <- event_data %>% | ||
dplyr::tibble() %>% | ||
tidyr::unnest(cols = "details") %>% | ||
dplyr::mutate(time = lubridate::as_datetime(as.integer(time / 1000))) | ||
|
||
# Force value column to be a character data type | ||
if ("value" %in% colnames(result)) { | ||
dplyr::mutate(result, value = format(value)) | ||
} else { | ||
# If there is no column, then it should still be a character data type | ||
dplyr::mutate(result, value = NA_character_) | ||
} | ||
} else { | ||
dplyr::tibble( | ||
app_name = character(), | ||
type = character(), | ||
session = character(), | ||
username = character(), | ||
id = character(), | ||
value = character(), | ||
time = lubridate::as_datetime(NULL, tz = "UTC") | ||
) | ||
} | ||
} | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Instrumented app with MongoDB backend | ||
|
||
This example application uses MongoDB as a provider for data storage. | ||
|
||
It is bundled with an example docker container provided by `docker-compose.yml`. | ||
The MongoDB instance has to be running for the application and analytics dashboard to work. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Use root/example as user/password credentials | ||
version: '3.1' | ||
|
||
services: | ||
|
||
mongo: | ||
image: mongo | ||
restart: always | ||
environment: | ||
MONGO_INITDB_ROOT_USERNAME: root | ||
MONGO_INITDB_ROOT_PASSWORD: example | ||
ports: | ||
- 27017:27017 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
library(shiny) | ||
library(shiny.semantic) | ||
library(semantic.dashboard) | ||
library(shinyjs) | ||
library(tidyr) | ||
library(dplyr) | ||
library(purrr) | ||
library(plotly) | ||
library(timevis) | ||
library(ggplot2) | ||
library(mgcv) | ||
library(config) | ||
library(DT) | ||
|
||
# Please install shiny.telemetry with all dependencies | ||
library(shiny.telemetry) | ||
|
||
# Default storage backend using MariaDB | ||
data_storage <- DataStorageMongoDB$new( | ||
username = "root", password = "example" | ||
) | ||
|
||
analytics_app(data_storage = data_storage) | ||
|
||
# shiny::shinyAppFile(system.file("examples", "mariadb", "mariadb_analytics.R", package = "shiny.telemetry")) # nolint: commented_code, line_length. |
Oops, something went wrong.