-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 66ce2f0
Showing
46 changed files
with
3,887 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
if (file.exists("renv")) { | ||
source("renv/activate.R") | ||
} else { | ||
# The `renv` directory is automatically skipped when deploying with rsconnect. | ||
message("No 'renv' directory found; renv won't be activated.") | ||
} | ||
|
||
# Allow absolute module imports (relative to the app root). | ||
options(box.path = getwd()) |
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,33 @@ | ||
on: | ||
workflow_dispatch: | ||
push: | ||
branches: add-webpage | ||
|
||
name: Quarto Publish | ||
|
||
defaults: | ||
run: | ||
working-directory: ./docs | ||
|
||
jobs: | ||
build-deploy: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
contents: write | ||
steps: | ||
- name: Check out repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Copy README | ||
run: cp ../README.md . | ||
|
||
- name: Set up Quarto | ||
uses: quarto-dev/quarto-actions/setup@v2 | ||
|
||
- name: Render and Publish | ||
uses: quarto-dev/quarto-actions/publish@v2 | ||
with: | ||
target: gh-pages | ||
path: docs | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
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,72 @@ | ||
name: Rhino Test | ||
on: push | ||
permissions: | ||
contents: read | ||
jobs: | ||
main: | ||
name: Run linters and tests | ||
runs-on: ubuntu-22.04 | ||
steps: | ||
- name: Checkout repo | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup system dependencies | ||
run: | | ||
packages=( | ||
# List each package on a separate line. | ||
) | ||
sudo apt-get update | ||
sudo apt-get install --yes "${packages[@]}" | ||
- name: Setup R | ||
uses: r-lib/actions/setup-r@v2 | ||
with: | ||
r-version: renv | ||
|
||
- name: Setup R dependencies | ||
uses: r-lib/actions/setup-renv@v2 | ||
|
||
- name: Setup Node | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: 20 | ||
|
||
- name: Lint R | ||
if: always() | ||
shell: Rscript {0} | ||
run: rhino::lint_r() | ||
|
||
- name: Lint JavaScript | ||
if: always() | ||
shell: Rscript {0} | ||
run: rhino::lint_js() | ||
|
||
- name: Lint Sass | ||
if: always() | ||
shell: Rscript {0} | ||
run: rhino::lint_sass() | ||
|
||
- name: Build JavaScript | ||
if: always() | ||
shell: Rscript {0} | ||
run: rhino::build_js() | ||
|
||
- name: Build Sass | ||
if: always() | ||
shell: Rscript {0} | ||
run: rhino::build_sass() | ||
|
||
- name: Run R unit tests | ||
if: always() | ||
shell: Rscript {0} | ||
run: rhino::test_r() | ||
|
||
- name: Run Cypress end-to-end tests | ||
if: always() | ||
uses: cypress-io/github-action@v6 | ||
with: | ||
working-directory: .rhino # Created by earlier commands which use Node.js | ||
start: npm run run-app | ||
project: ../tests | ||
wait-on: 'http://localhost:3333/' | ||
wait-on-timeout: 60 |
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 @@ | ||
.Rproj.user | ||
.Rhistory | ||
.RData | ||
.Ruserdata | ||
.DS_Store | ||
.Renviron |
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,5 @@ | ||
linters: | ||
linters_with_defaults( | ||
line_length_linter = line_length_linter(100), | ||
object_usage_linter = NULL # Does not work with `box::use()`. | ||
) |
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,3 @@ | ||
# Only use `dependencies.R` to infer project dependencies. | ||
* | ||
!dependencies.R |
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,7 @@ | ||
.github | ||
.lintr | ||
.renvignore | ||
.Renviron | ||
.rhino | ||
.rscignore | ||
tests |
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,9 @@ | ||
Copyright (C) 2024 Appsilon and Elkem | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
|
||
Except as contained in this notice, the name of Appsilon or Elkem shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Appsilon and Elkem. |
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,16 @@ | ||
Version: 1.0 | ||
|
||
RestoreWorkspace: Default | ||
SaveWorkspace: Default | ||
AlwaysSaveHistory: Default | ||
|
||
EnableCodeIndexing: Yes | ||
UseSpacesForTab: Yes | ||
NumSpacesForTab: 2 | ||
Encoding: UTF-8 | ||
|
||
RnwWeave: Sweave | ||
LaTeX: pdfLaTeX | ||
|
||
AutoAppendNewline: Yes | ||
StripTrailingWhitespace: Yes |
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,31 @@ | ||
# LogAnalyzer | ||
|
||
The LogAnalyzer open-source app is a simple, plug and play application developed first in collaboration with [Elkem](https://www.elkem.com/). The app provides an ability to get semantically coloured logs for applications deployed on Posit Connect by simply changing the default environment variables and deploying it on Posit Connect. Given the general usefulness of the app, we have decided to share it with the wider community to use and improve upon it. No more sifting through long text files; you can simply find the reds and see where things break. It has never been easier to investigate what goes wrong with your applications. | ||
|
||
# How it works? | ||
|
||
- The LogAnalyzer app uses the Posit Connect API to fetch logs for application run jobs, semantically colouring them so they are easier to read. | ||
- The only thing you need to set this up and use is the `CONNECT_API_KEY` set as an environment variable. The idea is that the key should come from either an admin account or someone with privileges to view all apps. Apps that are not available to a user will not have their logs available to them. | ||
- If you want to test the app locally, you will need to set the `CONNECT_SERVER` as an environment variable. When deployed, the `CONNECT_SERVER` is setup automatically for you. | ||
|
||
![LogAnalyzerDemo](https://github.com/Appsilon/LogAnalyzer/assets/26517718/90d1111d-006b-42db-8d8b-b55ee391cb21) | ||
|
||
# Credits | ||
It was our collaboration with <img src="https://github.com/Appsilon/LogAnalyzer/assets/26517718/b26fd60b-4989-4d31-a01e-5cf865f5ec9b" alt="Elkem" width="50"/> which led to the creation of this app. The initial idea came from use-cases where we realised we wanted to track all the logs and be able to read them properly since Posit Connect was the de facto deployment environment. When we made this app, we realised there was potential in sharing this with the rest of the community and invite everyone to use it and add it. We appreciate and thank Elkem for their openness to share it with the world. | ||
|
||
You can read more about Appsilon and Elkem's collaboration on our case study [here](https://www.appsilon.com/case-studies/refining-elkems-processes-with-advanced-data-analytics). | ||
|
||
## Appsilon | ||
|
||
<img src="https://avatars0.githubusercontent.com/u/6096772" align="right" alt="" width="6%" /> | ||
|
||
Appsilon is a **Posit (formerly RStudio) Full Service Certified Partner**.<br/> | ||
Learn more at [appsilon.com](https://appsilon.com). | ||
|
||
Get in touch [[email protected]](mailto:[email protected]) | ||
|
||
Explore the [Rhinoverse](https://rhinoverse.dev) - a family of R packages built around [Rhino](https://appsilon.github.io/rhino/)! | ||
|
||
<a href = "https://appsilon.us16.list-manage.com/subscribe?u=c042d7c0dbf57c5c6f8b54598&id=870d5bfc05" target="_blank"> | ||
<img src="https://raw.githubusercontent.com/Appsilon/website-cdn/gh-pages/shiny_weekly_light.jpg" alt="Subscribe for Shiny tutorials, exclusive articles, R/Shiny community events, and more."/> | ||
</a> |
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,2 @@ | ||
# Rhino / shinyApp entrypoint. Do not edit. | ||
rhino::app() |
Empty file.
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,184 @@ | ||
box::use( | ||
dplyr[filter], | ||
glue[glue], | ||
httr2[ | ||
req_auth_bearer_token, | ||
req_dry_run, | ||
req_perform, | ||
req_user_agent, | ||
request, | ||
resp_body_string | ||
], | ||
jsonlite[fromJSON], | ||
magrittr[`%>%`], | ||
) | ||
|
||
#' Simple function to get the access token from environment | ||
#' @return Character token, if present | ||
get_access_token <- function() { | ||
token <- Sys.getenv( | ||
"CONNECT_API_KEY", | ||
unset = "NO_TOKEN" | ||
) | ||
if (token == "NO_TOKEN" || token == "") { | ||
stop("Are you sure your CONNECT_API_KEY is set?") | ||
} else { | ||
token | ||
} | ||
} | ||
|
||
#' Simple function to make an API url | ||
#' @param host Character. Default CONNECT_SERVER set as an envvar | ||
#' @param endpoint Character. Default is "content" | ||
#' @param version Logical. Whether to use versioned API. Default is "v1" | ||
#' @return url for the API | ||
get_api_url <- function( | ||
host = Sys.getenv("CONNECT_SERVER"), | ||
endpoint = "content", | ||
version = "v1" | ||
) { | ||
glue("{host}__api__/{version}/{endpoint}/") | ||
} | ||
|
||
#' Function to get a list of all apps belonging to the token | ||
#' | ||
#' @param app_mode_filter Character. The filter for app_mode in the API | ||
#' response. Default is "shiny". | ||
#' @param endpoint Character. Default is "content" | ||
#' @param dry_run Logical. Whether to dry run the API for debugging. | ||
#' Default is FALSE | ||
#' @export | ||
get_app_list <- function( | ||
app_mode_filter = "shiny", | ||
endpoint = "content", | ||
dry_run = FALSE | ||
) { | ||
|
||
url <- get_api_url( | ||
endpoint = endpoint | ||
) | ||
|
||
api_request <- request(url) %>% | ||
req_user_agent("LogAnalyzer") %>% | ||
req_auth_bearer_token(get_access_token()) | ||
|
||
if (dry_run) { | ||
api_request %>% | ||
req_dry_run() | ||
} else { | ||
api_request %>% | ||
req_perform() %>% | ||
resp_body_string() %>% | ||
fromJSON() %>% | ||
filter(app_mode == app_mode_filter) | ||
} | ||
} | ||
|
||
#' Function to get a list of all jobs for a specific app | ||
#' | ||
#' @param guid Character. The guid for the app in question | ||
#' @param endpoint Character. Default is "content" | ||
#' @param dry_run Logical. Whether to dry run the API for debugging. | ||
#' Default is FALSE | ||
#' @export | ||
get_job_list <- function( | ||
guid = NULL, | ||
endpoint = "content", | ||
dry_run = FALSE | ||
) { | ||
|
||
url <- get_api_url( | ||
endpoint = endpoint | ||
) | ||
|
||
api_request <- request( | ||
glue("{url}{guid}/jobs") | ||
) %>% | ||
req_user_agent("LogAnalyzer") %>% | ||
req_auth_bearer_token(get_access_token()) | ||
|
||
if (dry_run) { | ||
api_request %>% | ||
req_dry_run() | ||
} else { | ||
api_request %>% | ||
req_perform() %>% | ||
resp_body_string() %>% | ||
fromJSON() | ||
} | ||
} | ||
|
||
#' Function to get a list of all logs for a job for a specific app | ||
#' | ||
#' @param guid Character. The guid for the app in question | ||
#' @param job_key Character. The key for the job in question | ||
#' @param endpoint Character. Default is "content" | ||
#' @param tail Logical. Whether to show the tail only for the logs | ||
#' @param dry_run Logical. Whether to dry run the API for debugging. | ||
#' Default is FALSE | ||
#' @export | ||
get_job_logs <- function( | ||
guid = NULL, | ||
job_key = NULL, | ||
endpoint = "content", | ||
tail = FALSE, | ||
dry_run = FALSE | ||
) { | ||
|
||
url <- get_api_url( | ||
endpoint = endpoint | ||
) | ||
|
||
api_request <- request( | ||
glue("{url}{guid}/jobs/{job_key}/{ifelse(tail, 'tail', 'log')}") | ||
) %>% | ||
req_user_agent("LogAnalyzer") %>% | ||
req_auth_bearer_token(get_access_token()) | ||
|
||
if (dry_run) { | ||
api_request %>% | ||
req_dry_run() | ||
} else { | ||
logs <- api_request %>% | ||
req_perform() %>% | ||
resp_body_string() %>% | ||
fromJSON() | ||
logs["entries"] %>% | ||
data.frame() | ||
} | ||
} | ||
|
||
#' Function to download the logfile for a specific app | ||
#' | ||
#' @param guid Character. The guid for the app in question | ||
#' @param job_key Character. The key for the job in quesrtion | ||
#' @param endpoint Character. Default is "content" | ||
#' @param dry_run Logical. Whether to dry run the API for debugging. | ||
#' Default is FALSE | ||
#' @export | ||
download_job_logs <- function( | ||
guid = NULL, | ||
job_key = NULL, | ||
endpoint = "content", | ||
dry_run = FALSE | ||
) { | ||
|
||
url <- get_api_url( | ||
endpoint = endpoint | ||
) | ||
|
||
api_request <- request( | ||
glue("{url}{guid}/jobs/{job_key}/download") | ||
) %>% | ||
req_user_agent("LogAnalyzer") %>% | ||
req_auth_bearer_token(get_access_token()) | ||
|
||
if (dry_run) { | ||
api_request %>% | ||
req_dry_run() | ||
} else { | ||
api_request %>% | ||
req_perform() %>% | ||
resp_body_string() | ||
} | ||
} |
Oops, something went wrong.