├── .gitignore ├── starter-kits ├── elastic │ ├── .env.example │ ├── data_sources.yaml │ ├── fluent-bit.conf │ ├── fp-elastic-starter-template.jsonnet │ └── docker-compose.yaml ├── loki │ ├── .env.example │ ├── data_sources.yaml │ ├── config.yaml │ ├── fp-loki-starter-template.jsonnet │ └── docker-compose.yaml ├── prometheus │ ├── .env.example │ ├── data_sources.yaml │ ├── prometheus.yaml │ ├── docker-compose.yaml │ └── fp-prom-starter-template.jsonnet ├── prometheus+loki │ ├── .env.example │ ├── prometheus.yaml │ ├── data_sources.yaml │ ├── config.yaml │ ├── docker-compose.yaml │ └── fp-prom-loki-starter-template.jsonnet └── README.md ├── assets ├── fp-logo.png ├── proxy-register.png ├── proxy-datasource.png ├── fp-logo.svg └── logo.svg ├── integrations └── PagerDuty │ ├── README.md │ └── lambda_function.py ├── templates ├── meeting-notes │ ├── README.md │ └── template.jsonnet ├── README.md ├── incident-analysis │ ├── README.md │ └── template.jsonnet ├── incident-response-pagerdutyV2 │ ├── README.md │ └── template.jsonnet └── incident-response-pagerdutyV3 │ ├── README.md │ └── template.jsonnet ├── proxy-kubernetes ├── configmap.yaml └── deployment.yaml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store -------------------------------------------------------------------------------- /starter-kits/elastic/.env.example: -------------------------------------------------------------------------------- 1 | FP_PROXY_TOKEN= -------------------------------------------------------------------------------- /starter-kits/loki/.env.example: -------------------------------------------------------------------------------- 1 | FP_PROXY_TOKEN=yourtokenhere -------------------------------------------------------------------------------- /starter-kits/prometheus/.env.example: -------------------------------------------------------------------------------- 1 | FP_PROXY_TOKEN=yourtokenhere -------------------------------------------------------------------------------- /starter-kits/prometheus+loki/.env.example: -------------------------------------------------------------------------------- 1 | FP_PROXY_TOKEN=yourtokenhere -------------------------------------------------------------------------------- /assets/fp-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiberplane/quickstart/HEAD/assets/fp-logo.png -------------------------------------------------------------------------------- /assets/proxy-register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiberplane/quickstart/HEAD/assets/proxy-register.png -------------------------------------------------------------------------------- /assets/proxy-datasource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiberplane/quickstart/HEAD/assets/proxy-datasource.png -------------------------------------------------------------------------------- /starter-kits/loki/data_sources.yaml: -------------------------------------------------------------------------------- 1 | - name: starter-loki 2 | description: Loki starterkit 3 | providerType: loki 4 | config: 5 | url: http://loki:3100 -------------------------------------------------------------------------------- /starter-kits/prometheus/data_sources.yaml: -------------------------------------------------------------------------------- 1 | - name: starter-prom 2 | description: Prometheus starterkit 3 | providerType: prometheus 4 | config: 5 | url: http://prometheus:9090 -------------------------------------------------------------------------------- /starter-kits/elastic/data_sources.yaml: -------------------------------------------------------------------------------- 1 | - name: elastic-starter 2 | description: ElasticSearch for starter kit 3 | providerType: elasticsearch 4 | config: 5 | url: http://elasticsearch:9200 6 | -------------------------------------------------------------------------------- /integrations/PagerDuty/README.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | Follow the instructions found in the [Fiberplane Documentation](https://docs.fiberplane.com/templates/pagerduty-integration) in order to use this integration. -------------------------------------------------------------------------------- /starter-kits/prometheus/prometheus.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | 4 | scrape_configs: 5 | - job_name: "prometheus" 6 | static_configs: 7 | - targets: ["localhost:9090"] 8 | 9 | - job_name: "node" 10 | static_configs: 11 | - targets: ["node-exporter:9100"] -------------------------------------------------------------------------------- /starter-kits/prometheus+loki/prometheus.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | 4 | scrape_configs: 5 | - job_name: "prometheus" 6 | static_configs: 7 | - targets: ["localhost:9090"] 8 | 9 | - job_name: "node" 10 | static_configs: 11 | - targets: ["node-exporter:9100"] 12 | -------------------------------------------------------------------------------- /templates/meeting-notes/README.md: -------------------------------------------------------------------------------- 1 | [Meeting Notes Template](./template.jsonnet) 2 | 3 | > A simple template for a meeting agenda, notes, and action items 4 | 5 | ## Template Documentation 6 | 7 | ### Template Arguments 8 | 9 | - `topic` - The subject of the meeting 10 | - `date` - Today's date 11 | -------------------------------------------------------------------------------- /starter-kits/prometheus+loki/data_sources.yaml: -------------------------------------------------------------------------------- 1 | - name: starter-prom 2 | description: Prometheus starterkit 3 | providerType: prometheus 4 | config: 5 | url: http://prometheus:9090 6 | 7 | - name: starter-loki 8 | description: Loki starterkit 9 | providerType: loki 10 | config: 11 | url: http://loki:3100 -------------------------------------------------------------------------------- /starter-kits/loki/config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http_listen_port: 9080 3 | grpc_listen_port: 0 4 | 5 | positions: 6 | filename: /tmp/positions.yaml 7 | 8 | clients: 9 | - url: http://loki:3100/loki/api/v1/push 10 | 11 | scrape_configs: 12 | - job_name: system 13 | static_configs: 14 | - targets: 15 | - localhost 16 | labels: 17 | job: varlogs 18 | __path__: /var/log/*log -------------------------------------------------------------------------------- /starter-kits/prometheus+loki/config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http_listen_port: 9080 3 | grpc_listen_port: 0 4 | 5 | positions: 6 | filename: /tmp/positions.yaml 7 | 8 | clients: 9 | - url: http://loki:3100/loki/api/v1/push 10 | 11 | scrape_configs: 12 | - job_name: system 13 | static_configs: 14 | - targets: 15 | - localhost 16 | labels: 17 | job: varlogs 18 | __path__: /var/log/*log -------------------------------------------------------------------------------- /starter-kits/elastic/fluent-bit.conf: -------------------------------------------------------------------------------- 1 | [INPUT] 2 | Name tail 3 | Path /var/log/*.log 4 | Read_from_Head true 5 | 6 | [OUTPUT] 7 | name es 8 | match * 9 | host elasticsearch 10 | port 9200 11 | replace_dots on 12 | retry_limit false 13 | logstash_format off 14 | logstash_prefix fluent-bit 15 | Suppress_Type_Name On 16 | -------------------------------------------------------------------------------- /starter-kits/README.md: -------------------------------------------------------------------------------- 1 | # Fiberplane Starter-Kits :rocket: 2 | 3 | Fiberplane starter-kits aim to help you get an experience of how Fiberplane can 4 | be used within your infrastructure to ease troubleshooting incidents. These use 5 | Docker Compose to run instances of Prometheus, Loki, Elastic and Fiberplane 6 | Daemon as Docker containers on your host of choice (Linux or MacOS) so that you 7 | can take it for a spin. 8 | 9 | The full documentation for using these can be found on our [documentation site](https://docs.fiberplane.com). 10 | -------------------------------------------------------------------------------- /proxy-kubernetes/configmap.yaml: -------------------------------------------------------------------------------- 1 | # configmap.yaml 2 | 3 | --- 4 | apiVersion: v1 5 | kind: ConfigMap 6 | metadata: 7 | name: fiberplane-proxy 8 | data: 9 | data_sources.yaml: | 10 | # Change this file to point to your actual data source(s) 11 | 12 | # You can add data sources using this format: 13 | # Data Source Name: 14 | # type: prometheus 15 | # options: 16 | # url: your prometheus URL 17 | 18 | # More data source types are coming soon! 19 | 20 | # The data source name will appear in the Fiberplane Studio 21 | - name: prometheus-prod 22 | description: Prometheus (Production) 23 | providerType: prometheus 24 | config: 25 | # Replace the following line with your Prometheus URL 26 | url: http://prometheus -------------------------------------------------------------------------------- /starter-kits/loki/fp-loki-starter-template.jsonnet: -------------------------------------------------------------------------------- 1 | // For documentation on Fiberplane Templates, see: https://github.com/fiberplane/templates 2 | local fp = import 'fiberplane.libsonnet'; 3 | local c = fp.cell; 4 | local fmt = fp.format; 5 | 6 | function( 7 | title='Your loki notebook 🚀 ' 8 | ) 9 | fp.notebook 10 | .new(title) 11 | .setTimeRangeRelative(minutes=60) 12 | .addLabels({ 13 | 'type': 'starter-kit', 14 | }) 15 | .addCells([ 16 | c.text(['This is a preview notebook that shows logs within /var/logs on your host. Make sure to select ', fmt.bold(['my Loki as a datasource in the top right']), '. Happy troubleshooting!!!']), 17 | c.h3(['System Logs']), 18 | c.loki('{filename="/var/log/system.log"}'), 19 | c.h3(['All logs from varlogs']), 20 | c.loki('{job="varlogs"}') 21 | ]) 22 | 23 | -------------------------------------------------------------------------------- /starter-kits/elastic/fp-elastic-starter-template.jsonnet: -------------------------------------------------------------------------------- 1 | // For documentation on Fiberplane Templates, see: https://github.com/fiberplane/templates 2 | local fp = import 'fiberplane.libsonnet'; 3 | local c = fp.cell; 4 | local fmt = fp.format; 5 | 6 | function( 7 | title='Your elastic notebook 🚀 ' 8 | ) 9 | fp.notebook 10 | .new(title) 11 | .setTimeRangeRelative(minutes=60) 12 | .addLabels({ 13 | 'type': 'starter-kit', 14 | }) 15 | .addCells([ 16 | c.text(['This is a preview notebook that shows logs within /var/logs on your host. Make sure to select ', fmt.bold(['my elastic as a datasource in the top right']), '. Happy troubleshooting!!!']), 17 | c.h3(['System Logs']), 18 | c.elasticsearch('log:"/var/log/system.log"'), 19 | c.h3(['All logs from varlogs']), 20 | c.elasticsearch('*') 21 | ]) 22 | -------------------------------------------------------------------------------- /starter-kits/loki/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | networks: 4 | loki: 5 | 6 | services: 7 | loki: 8 | image: grafana/loki:latest 9 | ports: 10 | - "3100:3100" 11 | command: -config.file=/etc/loki/local-config.yaml 12 | networks: 13 | - loki 14 | 15 | promtail: 16 | image: grafana/promtail:latest 17 | volumes: 18 | - /var/log:/var/log 19 | - ./config.yaml:/etc/promtail/config.yaml 20 | command: -config.file=/etc/promtail/config.yaml 21 | networks: 22 | - loki 23 | 24 | fpd: 25 | image: fiberplane/fpd:v2 26 | container_name: fpd 27 | restart: unless-stopped 28 | volumes: 29 | - ./data_sources.yaml:/app/data_sources.yaml 30 | command: 31 | - --token=${FPD_API_TOKEN:?err} 32 | networks: 33 | - loki 34 | depends_on: 35 | - loki 36 | - promtail 37 | -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | 3 | Fiberplane Templates are powerful tools to create programmatic DevOps workflows for monitoring, debugging your infrastructure, and responding to incidents. 4 | 5 | Fiberplane Templates are built using [Jsonnet data templating language](https://jsonnet.org/). You can find some useful examples to get you started in this repo. 6 | 7 | - [Incident Response](./incident-response-pagerduty) - a sample PagerDuty-to-Fiberplane workflow to help run your incident response 8 | - [Incident Analysis / Postmortem](./incident-analysis) - to help you analyze what went wrong and what steps to take to mediate or prevent the incident in the future 9 | - [Meeting Notes](./meeting-notes) - to run your weekly SRE meetings and reviews 10 | 11 | Want to contribute or request a template for another use case? Tell us by email at [hello@fiberplane.com](mailto:hello@fiberplane.com) or on [Discord](https://discord.gg/fAt2xgMSGS)! 12 | -------------------------------------------------------------------------------- /starter-kits/elastic/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | networks: 4 | elastic: 5 | 6 | services: 7 | fluent-bit: 8 | image: fluent/fluent-bit:latest 9 | volumes: 10 | - ./fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf 11 | - /var/log:/var/log 12 | ports: 13 | - "5170:5170" 14 | deploy: 15 | resources: 16 | limits: 17 | memory: 60m 18 | 19 | elasticsearch: 20 | image: elasticsearch:8.4.1 21 | restart: on-failure 22 | ports: 23 | - "9200:9200" 24 | environment: 25 | - discovery.type=single-node 26 | - "ES_JAVA_OPTS=-Xms256m -Xmx256m" 27 | - xpack.security.enabled=false 28 | deploy: 29 | resources: 30 | limits: 31 | memory: 1g 32 | depends_on: 33 | - fluent-bit 34 | 35 | fpd: 36 | image: fiberplane/fpd:v2 37 | restart: unless-stopped 38 | volumes: 39 | - ./data_sources.yaml:/app/data_sources.yaml 40 | command: 41 | - --status-check-interval=5s 42 | - --token=${FPD_API_TOKEN:?err} 43 | -------------------------------------------------------------------------------- /starter-kits/prometheus/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | networks: 4 | prom: 5 | 6 | services: 7 | node-exporter: 8 | image: prom/node-exporter:latest 9 | container_name: node-exporter 10 | restart: unless-stopped 11 | volumes: 12 | - /proc:/host/proc:ro 13 | - /sys:/host/sys:ro 14 | - /:/rootfs:ro 15 | expose: 16 | - 9100 17 | 18 | prometheus: 19 | image: prom/prometheus:latest 20 | container_name: prometheus 21 | restart: unless-stopped 22 | volumes: 23 | - ./prometheus.yaml:/etc/prometheus/prometheus.yaml 24 | command: 25 | - '--config.file=/etc/prometheus/prometheus.yaml' 26 | expose: 27 | - 9090 28 | depends_on: 29 | - node-exporter 30 | 31 | fpd: 32 | image: fiberplane/fpd:v2 33 | container_name: fpd 34 | restart: unless-stopped 35 | volumes: 36 | - ./data_sources.yaml:/app/data_sources.yaml 37 | command: 38 | - --token=${FPD_API_TOKEN:?err} 39 | depends_on: 40 | - prometheus 41 | - node-exporter 42 | -------------------------------------------------------------------------------- /templates/meeting-notes/template.jsonnet: -------------------------------------------------------------------------------- 1 | // For documentation on using Fiberplane Templates, see: 2 | // https://github.com/fiberplane/templates 3 | local fp = import 'fiberplane.libsonnet'; 4 | local c = fp.cell; 5 | 6 | function( 7 | // Any arguments to this function will be filled 8 | // in with values when the template is evaluated. 9 | // 10 | // You can replace fixed values anywhere in the 11 | // template with the argument names and the 12 | // values will be substituted accordingly. 13 | 14 | topic='', 15 | date='', 16 | ) 17 | fp.notebook 18 | .new('Meeting Notes: ' + topic + ' - ' + date) 19 | .setTimeRangeRelative(60) 20 | .addLabels({}) 21 | .addCells([ 22 | c.text('Attendees:'), 23 | c.h1('Agenda'), 24 | c.listItem.ordered(' ', startNumber=1), 25 | c.listItem.ordered(''), 26 | c.h1('Notes'), 27 | c.listItem.unordered(' '), 28 | c.listItem.unordered(''), 29 | c.h1('Action Items'), 30 | c.checkbox(' ', checked=false), 31 | c.checkbox('', checked=false), 32 | c.text(''), 33 | ]) 34 | -------------------------------------------------------------------------------- /templates/incident-analysis/README.md: -------------------------------------------------------------------------------- 1 | # [Incident Analysis / Postmortem Template](./template.jsonnet) 2 | 3 | > A template that can be used to guide teams through the incident analysis / postmortem process, focussing on the learnings gained from the incident. 4 | 5 | ## Template Documentation 6 | 7 | ### Template Arguments 8 | 9 | The template has four arguments which can be used to provide context for the incident being analysed. These are: 10 | 11 | - `incidentNumber` - This will add the incident number to the title of the notebook. Default value is `` 12 | - `incidentTitle` - This will add the incident name to the title of the notebook. Default value is `` 13 | - `serviceName` - This will populate the value for the label with the key `service` with the name of the service. Default value is `service_name` 14 | - `environmentName` - This will populate the value for the label with the key `environment` with the name of the environment. default value is `environment_name` 15 | 16 | ### Time Range 17 | 18 | The template defaults to the last hour. Change the value of `.setTimeRangeRelative(minutes=60)` to edit this 19 | -------------------------------------------------------------------------------- /templates/incident-response-pagerdutyV2/README.md: -------------------------------------------------------------------------------- 1 | # [Incident Response with Pagerduty Template](./template.jsonnet) 2 | 3 | > A template that can be used and / or altered to provide a consistent response to incidents. 4 | 5 | ## Template Documentation 6 | 7 | This is an example template that illustrates how Fiberplane can work with your alert manager to aid your incident response workflow. This template works with the PagerDuty Webhook integration (V2) that sends a trigger when the incident is triggered in PagerDuty. 8 | 9 | Setup the workflow: 0. (prerequisite) make sure you have the Fiberplane CLI installed; 10 | 11 | 1. Download the template.jsonnet file: `curl -Lo template.jsonnet https://raw.githubusercontent.com/fiberplane/quickstart/main/templates/incident-response-pagerdutyV2/template.jsonnet`; 12 | 2. Add the local template jsonnet file to your Fiberplane: 13 | $ fp templates create --title="Name of your template" /path/to/the/template.jsonnet 14 | -> copy the ID of the template 15 | 3. Create a trigger endpoint for the template: 16 | $ fp triggers create --title="Name of your trigger endpoint" --template-id=YOUR_TEMPLATE_ID 17 | 4. Grab the generated URL with the secret key and paste it to PagerDuty Webhook setup 18 | -------------------------------------------------------------------------------- /templates/incident-response-pagerdutyV3/README.md: -------------------------------------------------------------------------------- 1 | # [Incident Response with Pagerduty Template](./template.jsonnet) 2 | 3 | > A template that can be used and / or altered to provide a consistent response to incidents. 4 | 5 | ## Template Documentation 6 | 7 | This is an example template that illustrates how Fiberplane can work with your alert manager to aid your incident response workflow. This template works with the PagerDuty Webhook integration (V3) that sends a trigger when the incident is acknowledged in PagerDuty. 8 | 9 | Setup the workflow: 0. (prerequisite) make sure you have the Fiberplane CLI installed; 10 | 11 | 1. Download the template.jsonnet file: `curl -Lo template.jsonnet https://raw.githubusercontent.com/fiberplane/quickstart/main/templates/incident-response-pagerdutyV3/template.jsonnet`; 12 | 2. Add the local template jsonnet file to your Fiberplane: 13 | $ fp templates create --title="Name of your template" /path/to/the/template.jsonnet 14 | -> copy the ID of the template 15 | 3. Create a trigger endpoint for the template: 16 | $ fp triggers create --title="Name of your trigger endpoint" --template-id=YOUR_TEMPLATE_ID 17 | 4. Grab the generated URL with the secret key and paste it to PagerDuty Webhook setup 18 | -------------------------------------------------------------------------------- /proxy-kubernetes/deployment.yaml: -------------------------------------------------------------------------------- 1 | # deployment.yaml 2 | 3 | --- 4 | apiVersion: apps/v1 5 | kind: Deployment 6 | metadata: 7 | name: fiberplane-proxy 8 | labels: 9 | app: fiberplane-proxy 10 | spec: 11 | replicas: 1 12 | selector: 13 | matchLabels: 14 | app: fiberplane-proxy 15 | template: 16 | metadata: 17 | labels: 18 | app: fiberplane-proxy 19 | spec: 20 | containers: 21 | - name: fiberplane-proxy 22 | image: "fiberplane/proxy:v2" 23 | env: 24 | - name: TOKEN 25 | value: "" # <-------------------------------- REPLACE ME 26 | - name: DATA_SOURCES_PATH 27 | value: /app/config/data_sources.yaml 28 | - name: RUST_LOG 29 | value: proxy=debug 30 | volumeMounts: 31 | - name: data-sources 32 | mountPath: /app/config/data_sources.yaml 33 | subPath: data_sources.yaml 34 | volumes: 35 | - name: data-sources 36 | configMap: 37 | # Provide the name of the ConfigMap containing the files you want 38 | # to add to the container 39 | name: fiberplane-proxy 40 | items: 41 | - key: data_sources.yaml 42 | path: data_sources.yaml -------------------------------------------------------------------------------- /starter-kits/prometheus+loki/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | networks: 4 | default: 5 | name: fp 6 | external: true 7 | 8 | services: 9 | node-exporter: 10 | image: prom/node-exporter:latest 11 | ports: 12 | - "9100:9100" 13 | container_name: node-exporter 14 | restart: unless-stopped 15 | volumes: 16 | - /proc:/host/proc:ro 17 | - /sys:/host/sys:ro 18 | - /:/rootfs:ro 19 | 20 | prometheus: 21 | image: prom/prometheus:latest 22 | container_name: prometheus 23 | ports: 24 | - "9090:9090" 25 | restart: unless-stopped 26 | volumes: 27 | - ./prometheus.yaml:/etc/prometheus/prometheus.yaml 28 | command: 29 | - '--config.file=/etc/prometheus/prometheus.yaml' 30 | depends_on: 31 | - node-exporter 32 | 33 | loki: 34 | image: grafana/loki:latest 35 | ports: 36 | - "3100:3100" 37 | command: -config.file=/etc/loki/local-config.yaml 38 | 39 | promtail: 40 | image: grafana/promtail:latest 41 | volumes: 42 | - /var/log:/var/log 43 | - ./config.yaml:/etc/promtail/config.yaml 44 | command: -config.file=/etc/promtail/config.yaml 45 | 46 | fpd: 47 | image: fiberplane/fpd:v2 48 | container_name: fpd 49 | restart: unless-stopped 50 | volumes: 51 | - ./data_sources.yaml:/app/data_sources.yaml 52 | command: 53 | - --token=${FP_API_TOKEN:?err} 54 | depends_on: 55 | - prometheus 56 | - node-exporter 57 | - loki 58 | - promtail 59 | -------------------------------------------------------------------------------- /starter-kits/prometheus/fp-prom-starter-template.jsonnet: -------------------------------------------------------------------------------- 1 | // For documentation on Fiberplane Templates, see: https://github.com/fiberplane/templates 2 | local fp = import 'fiberplane.libsonnet'; 3 | local c = fp.cell; 4 | local fmt = fp.format; 5 | 6 | function( 7 | title='Your prometheus notebook 🚀 ' 8 | ) 9 | fp.notebook 10 | .new(title) 11 | .setTimeRangeRelative(minutes=15) 12 | .addLabels({ 13 | 'type': 'starter-kit', 14 | }) 15 | .addCells([ 16 | c.text(['This is a preview notebook that shows basic infrastructure data from the Prometheus instance you just set up using the Starter Kit. Make sure to select ', fmt.bold(['Prometheus as a datasource in the top right']), '. Happy troubleshooting!!!']), 17 | c.h3('Prometheus health check'), 18 | c.prometheus('up'), 19 | c.h3('CPU usage'), 20 | c.prometheus('(1 - avg(irate(node_cpu_seconds_total{mode="idle"}[1m])) by (instance)) * 100'), 21 | c.h3('Memory usage'), 22 | c.prometheus('(node_memory_MemTotal_bytes/1024/1024/1024) - (node_memory_MemAvailable_bytes/1024/1024/1024)'), 23 | c.h3('Disk usage'), 24 | c.prometheus('100 - ((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes)'), 25 | c.h3(['Total HTTP Requests', fmt.bold([])]), 26 | c.prometheus('rate(prometheus_http_requests_total[1m])'), 27 | c.h1('Next Steps'), 28 | c.text(['Now proceed to instrumenting your application to get metrics from your app. Prometheus provides client libraries in different languages to make it easier for you, find out more ', fmt.link(url='https://prometheus.io/docs/instrumenting/clientlibs/#', content=['here']), '.']), 29 | c.text(''), 30 | ]) 31 | 32 | -------------------------------------------------------------------------------- /starter-kits/prometheus+loki/fp-prom-loki-starter-template.jsonnet: -------------------------------------------------------------------------------- 1 | // For documentation on Fiberplane Templates, see: https://github.com/fiberplane/templates 2 | local fp = import 'fiberplane.libsonnet'; 3 | local c = fp.cell; 4 | local fmt = fp.format; 5 | 6 | function( 7 | title='Your prometheus + loki notebook 🚀 ' 8 | ) 9 | fp.notebook 10 | .new(title) 11 | .setTimeRangeRelative(minutes=15) 12 | .addLabels({ 13 | 'type': 'starter-kit', 14 | }) 15 | .addCells([ 16 | c.text(['This is a preview notebook that shows basic infrastructure data & logs from the Prometheus and Loki instances you just set up using the Starter Kit. Make sure to select ', fmt.bold(['my Prometheus & my Loki as datasources in the top right']), '. Happy troubleshooting!!!']), 17 | c.h3('Prometheus health check'), 18 | c.prometheus('up'), 19 | c.h3('CPU usage'), 20 | c.prometheus('(1 - avg(irate(node_cpu_seconds_total{mode="idle"}[1m])) by (instance)) * 100'), 21 | c.h3('Memory usage'), 22 | c.prometheus('(node_memory_MemTotal_bytes/1024/1024/1024) - (node_memory_MemAvailable_bytes/1024/1024/1024)'), 23 | c.h3('Disk usage'), 24 | c.prometheus('100 - ((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes)'), 25 | c.h3(['Total HTTP Requests', fmt.bold([])]), 26 | c.prometheus('rate(prometheus_http_requests_total[1m])'), 27 | c.h3(['System Logs']), 28 | c.loki('{filename="/var/log/system.log"}'), 29 | c.h3(['All logs from varlogs']), 30 | c.loki('{job="varlogs"}'), 31 | c.h1('Next Steps'), 32 | c.text(['Now proceed to instrumenting your application to get metrics from your app. Prometheus provides client libraries in different languages to make it easier for you, find out more ', fmt.link(url='https://prometheus.io/docs/instrumenting/clientlibs/#', content=['here']), '.']), 33 | ]) 34 | 35 | -------------------------------------------------------------------------------- /assets/fp-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /integrations/PagerDuty/lambda_function.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Documentation - https://docs.fiberplane.com/templates/pagerduty-integration 3 | ''' 4 | import json 5 | import requests #pick lambda runtime as py 3.7 for now, to be changed later on using a lambda layer with requests module in. 6 | 7 | ''' 8 | Function to invoke fp trigger 9 | ''' 10 | def post_to_fp(payload, fp_url): 11 | payload = json.dumps(payload) 12 | headers = { 13 | 'content-type': 'application/json' 14 | } 15 | response = requests.request("POST", fp_url, headers=headers, data=payload) 16 | return(response.json()) 17 | 18 | ''' 19 | Function to write notes in pagerduty incident 20 | ''' 21 | def post_to_pd(incident_id, notes, pd_api_key, userid): 22 | pd_url = f"https://api.pagerduty.com/incidents/{incident_id}/notes" 23 | payload = json.dumps({ 24 | "note": { 25 | "content": notes 26 | } 27 | }) 28 | headers = { 29 | 'Accept': 'application/vnd.pagerduty+json;version=2', 30 | 'Authorization': f'Token token={pd_api_key}', 31 | 'Content-Type': 'application/json', 32 | 'From': userid 33 | } 34 | response = requests.request("POST", pd_url, headers=headers, data=payload) 35 | return response.text 36 | 37 | ''' 38 | Function to get user email from pagerduty, invoked only when there is no email passed in pagerduty webhook custom header. 39 | ''' 40 | def get_pd_user(userid, pd_api_key): 41 | pd_url = f"https://api.pagerduty.com/users/{userid}" 42 | headers = { 43 | 'Accept': 'application/vnd.pagerduty+json;version=2', 44 | 'Authorization': f'Token token={pd_api_key}', 45 | 'Content-Type': 'application/json' 46 | } 47 | user_details = requests.request("GET", pd_url, headers=headers).json() 48 | return(user_details['user']['email']) 49 | 50 | def lambda_handler(event, context): 51 | payload = json.loads(event['body']) # get event details passed by pd from lambda request body 52 | trigger = event['headers']['fp-trigger'] # get fp trigger value from custom header passed by pagerduty 53 | pd_api_key = event['headers']['pd-apikey'] # get pd api key from custom header 54 | pd_incident = payload['event']['data']['id'] # get pd incident id 55 | if 'email' in event['headers']: # check if email is passed in custom headers, if yes, use it to write notes 56 | userid = event['headers']['email'] 57 | else: 58 | pd_user = payload['event']['agent']['id'] # if email not in custom headers, get email id of user who ack the incident 59 | userid = get_pd_user(pd_user, pd_api_key) 60 | fp_details = post_to_fp(payload,trigger) # capture response from fp notebook creation 61 | notes = fp_details['notebookUrl'] # notebook url parsed off fp response 62 | post_to_pd(pd_incident, notes, pd_api_key, userid) # send it back to pd api to write as a note 63 | 64 | return { 65 | 'statusCode': 200, 66 | 'body': json.dumps('Done stuff') 67 | } -------------------------------------------------------------------------------- /templates/incident-response-pagerdutyV2/template.jsonnet: -------------------------------------------------------------------------------- 1 | // This is an example template that illustrates how Fiberplane can work with your alert manager to aid your incident response workflow. This template works with the PagerDuty Webhook integration (V3) that sends a trigger when the incident is acknowledged in PagerDuty. 2 | // 3 | // To activate it: 4 | // 5 | // 0. (prerequisite) make sure you have the Fiberplane CLI installed; 6 | // 1. Pull down the repo and navigate to the template folder; 7 | // 2. Add the local template jsonnet file to your Fiberplane: 8 | // $ fp templates create --title="Name of your template" /path/to/the/template.jsonnet 9 | // -> copy the ID of the template 10 | // 3. Create a trigger endpoint for the template: 11 | // $ fp triggers create --title="Name of your trigger endpoint" --template-id=YOUR_TEMPLATE_ID 12 | // 4. Grab the generated URL with the secret key and paste it to PagerDuty Webhook setup 13 | 14 | local fp = import 'fiberplane.libsonnet'; 15 | local c = fp.cell; 16 | local fmt = fp.format; 17 | 18 | function( 19 | title='Pagerduty Incident - Webhook V2', 20 | messages=[], //PagerDuty sends an array of objects in v2 of the webhook 21 | ) 22 | fp.notebook 23 | .new('Incident ' + messages[0].incident.incident_number + ' - ' + messages[0].incident.title + ' on ' + messages[0].incident.impacted_services[0].summary) 24 | .setTimeRangeRelative(60) // sets time range to the 1h until the notebook has been created 25 | // 26 | // You can preselect the data sources for the notebook with the lines below (uncomment to use) 27 | // 28 | //.addDirectDataSource( 29 | // type='prometheus', 30 | // name='default', 31 | // url='https://url.to.your.prometheus', 32 | // ) 33 | // 34 | // .addProxyDataSource(type='prometheus') 35 | // 36 | .addLabels({ // we're also setting in some metadata that will help us organize the notebook 37 | 'incident':null, //shows that this notebook is for an incident 38 | 'status':messages[0].incident.status, //shows the status of the incident (usually:triggered) 39 | 'service':messages[0].incident.impacted_services[0].summary, //provides the name of the service NOTE THAT THIS WILL NOT DISPLAY IF THE SERVICE NAME HAS CHARACTERS NOT ALLOWED IN LABELS 40 | 'severity':messages[0].incident.urgency, // grabs the urgency 41 | }) 42 | .addCells([ 43 | c.text([fmt.bold(['Incident ID: ']), fmt.code([messages[0].log_entries[0].incident.id])]), //Pagerduty incident ID 44 | c.text(['Assigned to: ', messages[0].incident.assignments[0].assignee.summary]), //shows who the incident is assigned to, as per the Pagerduty escalation policy and schedule for the service 45 | c.h3('Summary'), 46 | c.text(''), 47 | c.divider(readOnly=true), 48 | c.h3(fmt.bold('Timeline')), 49 | c.text(messages[0].incident.created_at + ' - Incident start time'), 50 | c.divider(readOnly=true), 51 | c.h3('Actions'), 52 | c.checkbox('Action 1', checked=false), 53 | c.text(''), 54 | ]) -------------------------------------------------------------------------------- /templates/incident-response-pagerdutyV3/template.jsonnet: -------------------------------------------------------------------------------- 1 | // This is an example template that illustrates how Fiberplane can work with your alert manager to aid your incident response workflow. This template works with the PagerDuty Webhook integration (V3) that sends a trigger when the incident is acknowledged in PagerDuty. 2 | // 3 | // To activate it: 4 | // 5 | // 0. (prerequisite) make sure you have the Fiberplane CLI installed; 6 | // 1. Pull down the repo and navigate to the template folder; 7 | // 2. Add the local template jsonnet file to your Fiberplane: 8 | // $ fp templates create --title="Name of your template" /path/to/the/template.jsonnet 9 | // -> copy the ID of the template 10 | // 3. Create a trigger endpoint for the template: 11 | // $ fp triggers create --title="Name of your trigger endpoint" --template-id=YOUR_TEMPLATE_ID 12 | // 4. Grab the generated URL with the secret key and paste it to PagerDuty Webhook setup 13 | 14 | local fp = import 'fiberplane.libsonnet'; 15 | local c = fp.cell; 16 | local fmt = fp.format; 17 | 18 | function( 19 | title='PagerDuty Incident - Webhook V3', 20 | event={}, // PagerDuty sends the Webhook payload as a JSON object 21 | ) 22 | fp.notebook 23 | .new('Incident #' + event.data.number + ': ' + event.data.title + ' - ' + event.data.service.summary,) 24 | .setTimeRangeRelative(60) // sets time range to the 1h until the notebook has been created 25 | // 26 | // You can preselect the data sources for the notebook with the lines below (uncomment to use) 27 | // 28 | //.addDirectDataSource( 29 | // type='prometheus', 30 | // name='default', 31 | // url='https://url.to.your.prometheus', 32 | // ) 33 | // 34 | // .addProxyDataSource(type='prometheus') 35 | // 36 | .addLabels({ // we're also setting in some metadata that will help us organize the notebook 37 | 'type': event.data.type, // gets the type of the event (usually: incident) 38 | 'service-id': event.data.service.id, // gets the id of the service as specified in PagerDuty 39 | 'priority': event.data.priority.summary, // P1, P2 etc. Make sure you have Priorities enabled on PagerDuty 40 | 'urgency': event.data.urgency, // grabs the urgency 41 | 'status': event.data.status, // grabs the status of the incident from PagerDuty (usually: acknowledged) 42 | }) 43 | .addCells([ 44 | c.text([fmt.bold(['PagerDuty URL: ']), event.data.html_url]), // link back to the incident on PagerDuty 45 | c.text([fmt.bold(['Incident ID: ']), fmt.code([event.data.id])]), 46 | c.text([fmt.bold(['Assigned to: ']), event.data.assignees[0].summary,]), //shows who the incident is assigned to, as per the Pagerduty escalation policy and schedule for the service 47 | c.h3('Summary'), 48 | c.text(''), 49 | c.divider(readOnly=true), 50 | c.h3(fmt.bold('Timeline')), 51 | c.text(event.data.created_at + ' - Incident triggered'), 52 | c.text([fmt.highlight([event.occurred_at]), ' - Incident acknowledged (by: ', event.agent.summary, ')']), 53 | c.divider(readOnly=true), 54 | c.h3('Actions'), 55 | c.checkbox('Action 1', checked=false), 56 | c.text(''), 57 | ]) -------------------------------------------------------------------------------- /templates/incident-analysis/template.jsonnet: -------------------------------------------------------------------------------- 1 | local fp = import 'fiberplane.libsonnet'; 2 | local c = fp.cell; 3 | local fmt = fp.format; 4 | 5 | function( 6 | // Any arguments to this function will be filled 7 | // in with values when the template is evaluated. 8 | // 9 | // You can replace fixed values anywhere in the 10 | // template with the argument names and the 11 | // values will be substituted accordingly. 12 | 13 | incidentNumber='', 14 | incidentTitle='', 15 | serviceName='service_name', 16 | environmentName='environent_name', 17 | 18 | ) 19 | fp.notebook 20 | .new('Incident Analysis: ' + incidentNumber + ' - ' + incidentTitle) 21 | .setTimeRangeRelative(minutes=60) 22 | .addLabels({ 23 | type: 'incident-analysis', 24 | service: serviceName, 25 | environment: environmentName, 26 | }) 27 | // You can preselect the data sources for the notebook with the lines below (uncomment to use) 28 | // 29 | //.addDirectDataSource( 30 | // type='prometheus', 31 | // name='default', 32 | // url='https://url.to.your.prometheus', 33 | // ) 34 | // 35 | // .addProxyDataSource(type='prometheus') 36 | // 37 | .addCells([ 38 | c.h1('Incident Overview'), 39 | c.text(fmt.italics('A summary of the incident. How did it start? What happened? You can add a timeline in the timeline section at the end of the document so keep this brief')), 40 | c.h1('Impact'), 41 | c.text(fmt.italics('What was the impact? Did users get errors when performing certain actions? Was there a total loss of service? How long was this for? Use graphs to show this for context')), 42 | c.h1('Contributing factors'), 43 | c.text(fmt.italics("An incident occurs as the result of a sequence of events, it's rarely one thing. All contributing causes should be listed here. It's important that these are free of blame on people or teams. Focus on what happened, how the incident occurred and the processes followed in resolving it E.g")), 44 | c.listItem.unordered("'an incorrect configuration was applied'"), 45 | c.listItem.unordered("'the application hit a thread deadlock scenario' "), 46 | c.listItem.unordered("'the application only runs in one region'"), 47 | c.listItem.unordered("'High load uncovered a memory leak that occurs when users perform action X' "), 48 | c.listItem.unordered("'Application servers were no longer available'"), 49 | c.listItem.unordered("'Our infrastructure host suffered a failure'"), 50 | c.h1('What did we learn?'), 51 | c.text(fmt.italics("Incidents are one of the best opportunities for an organisation to learn so it's important to consider what you can learn from this incident. Consider the following questions as you walk through the timeline")), 52 | c.listItem.unordered('Did the existing processes provide adequate protection to prevent failure scenarios?'), 53 | c.listItem.unordered('Were the incident responders adequately equipped to deal with the incident?'), 54 | c.listItem.unordered('How did we identify what was happening? '), 55 | c.listItem.unordered('Was it easy to get to this understanding?'), 56 | c.listItem.unordered('What was our thinking when we took this action?'), 57 | c.listItem.unordered('What would we do differently if we came across this incident again?'), 58 | c.listItem.unordered('What went well? How can we emphasise this in future incidents?'), 59 | c.h1('Actions'), 60 | c.text(fmt.italics('List any actions that can be taken to build upon the learnings. Ideally get these assigned and added to any system you use for tracking planned work e.g linear, JIRA etc')), 61 | c.listItem.unordered('Action 1'), 62 | c.listItem.unordered('Action 2...'), 63 | c.divider(), 64 | c.h1('Timeline'), 65 | c.text(fmt.italics('This section should contain a timeline of the events of this incident. This should cover when the incident started, when you became aware and then a factual list of key events up to the incident resolution.')), 66 | c.h1('Fix'), 67 | c.text(fmt.italics('List the actions taken that remediated this incident')), 68 | ]) 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Fiberplane Logo 3 |
4 |
5 | 6 | Fiberplane is a collaborative notebook that connects to your observability stack and helps you monitor and debug your infrastructure. Fiberplane is currently available for the Web in closed beta - you can sign up for early access 👉 **[here](https://fiberplane.dev)**. 7 | 8 | You can explore a Fiberplane Notebook by simply going to [fp.new](https://fp.new) in the address bar of your browser, however, in order to save your notebook or query your observability data you will need to create an account and establish access to your infrastructure. 9 | 10 | ### How Fiberplane works 11 | 12 | Fiberplane accesses your infrastructure through Proxy, a lightweight package, [available as a Docker image](https://hub.docker.com/r/fiberplane/fpd), that once installed allows you to query your observability data from your Notebook. 13 | 14 | Whenever you execute a query in the notebook: 15 | 16 | 1. The query is forwarded to the Fiberplane Proxy in your cluster; 17 | 2. The Proxy then queries the data source (e.g. your Prometheus or Elastic instance); 18 | 3. The Proxy processes, encrypts, and then returns the data back to the Studio. 19 | 20 | \***Note:**\* Fiberplane Proxy is currently optimized to work with Kubernetes and Prometheus. Elasticsearch, Loki and more providers are coming soon. 21 | 22 | ## ⚡️ Setting up the Fiberplane Proxy with the CLI 23 | 24 | This guide will walk you through how to set up the Fiberplane Proxy and install it in your Kubernetes cluster or run it locally for testing purposes. 25 | 26 | #### What is in this repo? 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
integrations/Available plugins that can work with Fiberplane Templates
starter-kits/Sample docker-compose files to start up your Prometheus, Elasticsearch, Loki instances
templates/Sample Fiberplane templates to help get you started building workflows
42 | 43 | ### Pre-requisite: Download the Fiberplane CLI (beta) 44 | 45 | To work with Fiberplane Templates and setup Providers you will need to install the Fiberplane CLI. You can download and install `fp` with one command: 46 | 47 | Either Homebrew: 48 | 49 | ```bash 50 | brew install fiberplane/tap/fp 51 | ``` 52 | 53 | or install script: 54 | 55 | ```bash 56 | curl --proto '=https' --tlsv1.2 -sSf https://fp.dev/install.sh | sh 57 | ``` 58 | 59 |
60 | Alternatively: Download the latest binaries directly with cURL (click to expand) 61 | 62 | Mac (Apple Silicon): 63 | 64 | ```shell 65 | curl -O https://fp.dev/fp/latest/aarch64-apple-darwin/fp 66 | chmod 755 ./fp 67 | ``` 68 | 69 | Mac (Intel): 70 | 71 | ```shell 72 | curl -O https://fp.dev/fp/latest/x86_64-apple-darwin/fp 73 | chmod 755 ./fp 74 | ``` 75 | 76 | Linux / Windows (WSL): 77 | 78 | ```shell 79 | curl -O https://fp.dev/fp/latest/x86_64-unknown-linux-gnu/fp 80 | chmod 755 ./fp 81 | ``` 82 | 83 |
84 | 85 | ### Step 1: Authenticate the CLI 86 | 87 | You will need to authenticate the downloaded CLI with your Fiberplane account so you can create and register the Proxies. Simply type: 88 | 89 | ```shell 90 | fp login 91 | ``` 92 | 93 | You will be then prompted to login with your account. When you complete the login you can safely close the window. 94 | 95 | ### Step 2: Register an `fpd` (Fiberplane Daemon) with Fiberplane 96 | 97 | In order for `fpd` to receive queries from Fiberplane Notebooks, it needs to be authorized. This step will generate a **Daemon API Token** that will be needed in later steps. 98 | 99 | To register an `fpd` run a command `fp daemon create`: 100 | 101 | ``` 102 | $ fp daemon create 103 | Added proxy "robust-antelope" # generates a random name 104 | Proxy API Token: XXX_XX # and a token - save this for later! 105 | ``` 106 | 107 | 108 | ### Step 3: Run the Daemon locally for testing 109 | 110 | 1. Make sure you have [Docker](https://docs.docker.com/get-docker/) installed. 111 | 2. Create a `data_sources.yaml` in the current directory in the following format: 112 | 113 | ```yaml 114 | # data_sources.yaml 115 | # 116 | # Replace the following line with the name of the data source 117 | - name: prometheus-prod 118 | description: Prometheus (Production) 119 | providerType: prometheus 120 | config: 121 | # Replace the following line with your Prometheus URL 122 | url: http://prometheus 123 | ``` 124 | 125 | 126 | 3. Run the following command replacing `` with the `fpd` API Token created earlier: 127 | 128 | ```bash 129 | docker run \ 130 | -v "$PWD/data_sources.yaml:/app/data_sources.yaml" \ 131 | fiberplane/fpd:v2 \ 132 | --token= 133 | ``` 134 | 135 | ## Feedback and support 136 | 137 | We're always looking to improve our onboarding experience! Please report any issues and share your feedback by either: 138 | 139 | - emailing us at [support@fiberplane.com](mailto:support@fiberplane.com). 140 | - submitting an issue here on Github. 141 | -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | --------------------------------------------------------------------------------