{"id":13416531,"url":"https://github.com/eon01/DoMonit","last_synced_at":"2025-03-15T00:31:03.883Z","repository":{"id":50211010,"uuid":"65134730","full_name":"eon01/DoMonit","owner":"eon01","description":"A Deadly Simple Docker Monitoring Wrapper For Docker API","archived":false,"fork":false,"pushed_at":"2021-06-01T21:57:21.000Z","size":102,"stargazers_count":75,"open_issues_count":5,"forks_count":15,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-07-31T21:57:08.362Z","etag":null,"topics":["cloud","docker","docker-api","monitoring","python-wrapper","wrapper"],"latest_commit_sha":null,"homepage":"https://medium.com/@eon01/monitoring-docker-with-python-domonit-34440b8c6830","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eon01.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-07T13:30:49.000Z","updated_at":"2024-07-07T18:48:03.000Z","dependencies_parsed_at":"2022-09-01T04:31:22.378Z","dependency_job_id":null,"html_url":"https://github.com/eon01/DoMonit","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2FDoMonit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2FDoMonit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2FDoMonit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2FDoMonit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eon01","download_url":"https://codeload.github.com/eon01/DoMonit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243667692,"owners_count":20328032,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloud","docker","docker-api","monitoring","python-wrapper","wrapper"],"created_at":"2024-07-30T21:01:00.290Z","updated_at":"2025-03-15T00:31:03.642Z","avatar_url":"https://github.com/eon01.png","language":"Python","readme":"# DoMonit\n\nA deadly simple monitoring tool for Docker - Using A Python Wrapper For Docker API.\n[The Blog Post](https://medium.com/@eon01/monitoring-docker-with-python-domonit-34440b8c6830)\n\n# Compatibility\n\nA Python wrapper for Dokcer API 1.24 compatible with Docker 1.12.x and later.\n\n# Purpose \n\nThe purpose is to write python scripts easily for monitoring all of your Docker containers (running in a Linux distibution - other OS are coming soon in the roadmap of development).\n\n# The Wrapper\n\nThis is the Alpha, moving to Beta very very soon :-)\n\nThe wrapper contains these classes:\n\n```\napi/\n├── changes.py\n├── containers.py\n├── errors.py\n├── ids.py\n├── inspect.py\n├── logs.py\n├── process.py\n└── stats.py\n```\n\nWhere :\n\n**Containers** : List containers\n\n**Inspect** : Return low-level information on the container id\n\n**Ids** : Return containers IDs\n\n**Logs** : Get stdout and stderr logs from the container id\n\n**Process** : List processes running inside the container id. On Unix systems this is done by running the ps command. This endpoint is not supported on Windows.\n\n**Stats** : This endpoint returns a live stream of a container’s resource usage statistics.\n\n# Using virtualenv:\n\n```\nvirtualenv DoMonit\ncd DoMonit \ngit clone https://github.com/eon01/DoMonit.git\n. bin/activate\ncd DoMonit\npip install -r requirements.txt\n#To Test:\npython examples.py\n```\n\n# Example\n\nThis is an example script:\n\n```\nfrom api.containers import Containers\nfrom api.ids import Ids\nfrom api.inspect import Inspect\nfrom api.logs import Logs\nfrom api.process import Process\nfrom api.changes import Changes\nfrom api.stats import Stats\n\n\nimport json\n\n\nc = Containers()\ni = Ids()\n\nprint (\"Number of containers is : %s \" % (sum(1 for i in i.ids())))\n\nif __name__ == \"__main__\":\n\n    for c_id in i.ids():\n\n        ins = Inspect(c_id)\n        sta = Stats(c_id)\n        proc = Process(c_id, ps_args = \"aux\")\n\n\n\n        # Container name\n        print (\"\\n#Container name\")\n        print ins.name()\n \n        # Container id\n        print (\"\\n#Container id\")\n        print ins.id()\n\n        # Memory usage\n        mem_u = sta.usage()\n\n        # Memory limit\n        mem_l = sta.limit()\n\n        # Memory usage %\n        print (\"\\n#Memory usage %\")\n        print  int(mem_u)*100/int(mem_l)\n\n\n        # The number of times that a process of the cgroup triggered a \"major fault\"\n        print (\"\\n#The number of times that a process of the cgroup triggered a major fault\")\n        print sta.pgmajfault()\n  \n\n        # Same output as ps aux in *nix\n        print(\"\\n#Same output as ps aux in *nix\")\n        print proc.ps()\n```\n\nFor the following 5 running containers:\n\n```\ndocker ps\nCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES\n1a29e9652822        instavote/vote      \"gunicorn app:app -b \"   12 seconds ago      Up 11 seconds       80/tcp, 100/tcp     vote_webapp_3\n6ca598188d1a        instavote/vote      \"gunicorn app:app -b \"   12 seconds ago      Up 11 seconds       80/tcp, 100/tcp     vote_webapp_4\n7f1a6bfaf95b        instavote/vote      \"gunicorn app:app -b \"   12 seconds ago      Up 11 seconds       80/tcp, 100/tcp     vote_webapp_5\ne3a7066ba953        instavote/vote      \"gunicorn app:app -b \"   6 days ago          Up 5 hours          80/tcp, 100/tcp     vote_webapp_2\n1e557c8dc5f7        instavote/vote      \"gunicorn app:app -b \"   6 days ago          Up 5 hours          80/tcp, 100/tcp     vote_webapp_1\n```\n\nthe execution result of the example above is:\n\n\n```\nNumber of containers is : 5 \n\n#Container name\n/vote_webapp_3\n\n#Container id\n1a29e9652822447a440799306f4edb65003bca9cdea4c56e1e0ba349d5112d3e\n\n#Memory usage %\n0.697797903077\n\n#The number of times that a process of the cgroup triggered a major fault\n15\n\n#Same output as ps aux in *nix\n{u'Processes': [[u'root', u'26636', u'0.0', u'0.2', u'76808', u'16228', u'?', u'Ss', u'15:43', u'0:00', u'/usr/local/bin/python2 /usr/local/bin/gunicorn app:app -b 0.0.0.0:80 --log-file - --access-logfile - --workers 4 --keep-alive 0'], [u'root', u'26773', u'0.0', u'0.2', u'88776', u'19976', u'?', u'S', u'15:43', u'0:00', u'/usr/local/bin/python2 /usr/local/bin/gunicorn app:app -b 0.0.0.0:80 --log-file - --access-logfile - --workers 4 --keep-alive 0'], [u'root', u'26784', u'0.0', u'0.2', u'88572', u'19800', u'?', u'S', u'15:43', u'0:00', u'/usr/local/bin/python2 /usr/local/bin/gunicorn app:app -b 0.0.0.0:80 --log-file - --access-logfile - --workers 4 --keep-alive 0'], [u'root', u'26787', u'0.0', u'0.2', u'88568', u'19816', u'?', u'S', u'15:43', u'0:00', u'/usr/local/bin/python2 /usr/local/bin/gunicorn app:app -b 0.0.0.0:80 --log-file - --access-logfile - --workers 4 --keep-alive 0'], [u'root', u'26793', u'0.0', u'0.2', u'88572', u'19828', u'?', u'S', u'15:43', u'0:00', u'/usr/local/bin/python2 /usr/local/bin/gunicorn app:app -b 0.0.0.0:80 --log-file - --access-logfile - --workers 4 --keep-alive 0']], u'Titles': [u'USER', u'PID', u'%CPU', u'%MEM', u'VSZ', u'RSS', u'TTY', u'STAT', u'START', u'TIME', u'COMMAND']}\n\n...etc\n```\n\n\n# Testing Docker Events Stream Wrapper\n\nThis is a simple example:\n\n```\n#!/usr/bin/env python\n\nfrom domonit.events import Events\n\n# Events is a stream of json sent by Docker API. In the Events class, we are only streaming in the same way the Docker events like Docker API make it.\n\ne = Events()\nevents = e.events()\n\nfor event in events:\n    print event\n```\n\nThe event: \n\n```\n{\"Type\":\"network\",\"Action\":\"create\",\"Actor\":{\"ID\":\"a4a1ccb5c4a39ae64f46118e9e245b8cf516184571b7f7ccd6a406c20e735cb1\",\"Attributes\":{\"name\":\"test\",\"type\":\"bridge\"}},\"time\":1481460602,\"timeNano\":1481460602475845939}\n```\n\nis reported by the network creation:\n\n```\ndocker network create test\n```\n\n![](images/events.png)\n\n\n# DoMonit Functions\n\nFor better uderstanfing and visibility, I used Python ```dir()``` here to list the different functions of every class under ```api/*```\n\n```\npython dir.py\n\nContainers()\n['__doc__', '__init__', '__module__', 'base', 'command', 'containers', 'created', 'host_config', 'image', 'image_id', 'labels', 'mounts', 'names', 'network_settings', 'ports', 'resp', 'session', 'status', 'url']\n\n\nIds()\n['__doc__', '__init__', '__module__', 'base', 'ids', 'resp', 'session', 'url']\n\n\nInspect()\n['__doc__', '__init__', '__module__', 'app_armor_profile', 'args', 'attach_stderr', 'attach_stdin', 'base', 'cmd', 'container_id', 'created', 'domainname', 'driver', 'entrypoint', 'env', 'exec_ids', 'exposed_ports', 'host_config_binds', 'host_config_blkio_device_read_bps', 'host_config_blkio_device_write_bps', 'host_config_blkio_device_write_iops', 'host_config_blkio_weight_device', 'host_config_cap_add', 'host_config_cap_drop', 'host_config_container_id_file', 'host_config_cpu_percent', 'host_config_cpu_period', 'host_config_cpu_shares', 'host_config_cpuset_cpus', 'host_config_cpuset_mems', 'host_config_devices', 'host_config_dns', 'host_config_dns_options', 'host_config_dns_search', 'host_config_extra_hosts', 'host_config_host_config_shm_size', 'host_config_ipc_mode', 'host_config_kernel_memory', 'host_config_links', 'host_config_log_config_config', 'host_config_log_config_type', 'host_config_lxc_conf', 'host_config_maximum_iobps', 'host_config_maximum_iops', 'host_config_memory', 'host_config_memory_reservation', 'host_config_memory_swap', 'host_config_network_mode', 'host_config_oom_kill_disable', 'host_config_oom_score_adj', 'host_config_pid_mode', 'host_config_port_bindings', 'host_config_privileged', 'host_config_publish_all_ports', 'host_config_readonly_rootfs', 'host_config_restart_policy_maximum_retry_count', 'host_config_restart_policy_name', 'host_config_security_opt', 'host_config_storage_opt', 'host_config_sysctls', 'host_config_ulimits', 'host_config_volume_driver', 'host_config_volumes_from', 'hostname', 'hostname_path', 'hosts_path', 'id', 'image', 'inspect', 'labels', 'log_path', 'mac_address', 'mount_label', 'mounts', 'name', 'network_disabled', 'network_settings_bridge', 'network_settings_endpoint_id', 'network_settings_gateway', 'network_settings_global_ipv6_address', 'network_settings_global_ipv6_prefixLen', 'network_settings_hairpin_mode', 'network_settings_ip_address', 'network_settings_ip_prefixLen', 'network_settings_ipv6_gateway', 'network_settings_link_local_ipv6_address', 'network_settings_link_local_ipv6_prefix_len', 'network_settings_mac_address', 'network_settings_networks', 'network_settings_ports', 'network_settings_sandbox_id', 'network_settings_sandbox_key', 'network_settings_secondary_ip_addresses', 'network_settings_secondary_ipv6_addresses', 'on_build', 'open_stdin', 'path', 'process_label', 'resolv_conf_path', 'resp', 'restart_count', 'session', 'state_dead', 'state_error', 'state_exit_code', 'state_finished_at', 'state_oom_killed', 'state_paused', 'state_pid', 'state_restarting', 'state_running', 'state_started_at', 'state_status', 'stdin_once', 'stop_signal', 'tty', 'url', 'user', 'volumes', 'working_dir']\n\n\nStats()\n['__doc__', '__init__', '__module__', 'active_anon', 'active_file', 'base', 'blkio_stats', 'cache', 'container_id', 'cpu_stats', 'failcnt', 'hierarchical_memory_limit', 'inactive_anon', 'inactive_file', 'interfaces', 'limit', 'mapped_file', 'max_usage', 'memory_stats', 'networks', 'percpu_percpu_usage', 'percpu_period', 'percpu_stats', 'percpu_system_cpu_usage', 'percpu_throttled_periods', 'percpu_throttled_time', 'percpu_throttling_data', 'percpu_total_usage', 'percpu_usage', 'percpu_usage_in_kernelmode', 'percpu_usage_in_usermode', 'period', 'pgfault', 'pgmajfault', 'pgpgin', 'pgpgout', 'pids_stats_current', 'read', 'resp', 'rss', 'rss_huge', 'rx_bytes', 'rx_dropped', 'rx_errors', 'rx_packets', 'session', 'stats', 'stream', 'system_cpu_usage', 'throttled_periods', 'throttled_time', 'throttling_data', 'total_active_anon', 'total_active_file', 'total_cache', 'total_inactive_anon', 'total_inactive_file', 'total_mapped_file', 'total_pgfault', 'total_pgmajfault', 'total_pgpgin', 'total_pgpgout', 'total_rss', 'total_rss_huge', 'total_unevictable', 'total_usage', 'total_writeback', 'tx_bytes', 'tx_dropped', 'tx_errors', 'tx_packets', 'unevictable', 'url', 'usage', 'usage_in_kernelmode', 'usage_in_usermode', 'writeback']\n\n\nProcess()\n['__doc__', '__init__', '__module__', 'base', 'container_id', 'processes', 'ps', 'ps_args', 'resp', 'session', 'titles', 'url']\n\n\nLogs()\n['__doc__', '__init__', '__module__', 'base', 'container_id', 'details', 'follow', 'logs', 'resp', 'session', 'since', 'stderr', 'stdout', 'tail', 'timestamps', 'url']\n\n\nChanges()\n['__doc__', '__init__', '__module__', 'base', 'changes', 'container_id', 'resp', 'session', 'url']\n\n\nEvents()\n['__doc__', '__init__', '__module__', 'base', 'events', 'resp', 'session', 'url']\n\n```\n\n\n# Naming Conventions\n\nLet's take the example of the \"inspect\" call.\nDocer replies with data similar to the following one:\n\n```\n{\n    \"AppArmorProfile\": \"\",\n    \"Args\": [\n        \"-c\",\n        \"exit 9\"\n    ],\n    \"Config\": {\n        \"AttachStderr\": true,\n        \"AttachStdin\": false,\n        \"AttachStdout\": true,\n        \"Cmd\": [\n            \"/bin/sh\",\n            \"-c\",\n            \"exit 9\"\n        ],\n        \"Domainname\": \"\",\n        \"Entrypoint\": null,\n        \"Env\": [\n            \"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n        ],\n        \"ExposedPorts\": null,\n        \"Hostname\": \"ba033ac44011\",\n        \"Image\": \"ubuntu\",\n        \"Labels\": {\n            \"com.example.vendor\": \"Acme\",\n            \"com.example.license\": \"GPL\",\n            \"com.example.version\": \"1.0\"\n        },\n        \"MacAddress\": \"\",\n        \"NetworkDisabled\": false,\n        \"OnBuild\": null,\n        \"OpenStdin\": false,\n        \"StdinOnce\": false,\n        \"Tty\": false,\n        \"User\": \"\",\n        \"Volumes\": {\n            \"/volumes/data\": {}\n        },\n        \"WorkingDir\": \"\",\n        \"StopSignal\": \"SIGTERM\"\n    },\n    \"Created\": \"2015-01-06T15:47:31.485331387Z\",\n    \"Driver\": \"devicemapper\",\n    \"ExecIDs\": null,\n    \"HostConfig\": {\n        \"Binds\": null,\n        \"MaximumIOps\": 0,\n        \"MaximumIOBps\": 0,\n        \"BlkioWeight\": 0,\n        \"BlkioWeightDevice\": [{}],\n        \"BlkioDeviceReadBps\": [{}],\n        \"BlkioDeviceWriteBps\": [{}],\n        \"BlkioDeviceReadIOps\": [{}],\n        \"BlkioDeviceWriteIOps\": [{}],\n        \"CapAdd\": null,\n        \"CapDrop\": null,\n        \"ContainerIDFile\": \"\",\n        \"CpusetCpus\": \"\",\n        \"CpusetMems\": \"\",\n        \"CpuPercent\": 80,\n        \"CpuShares\": 0,\n        \"CpuPeriod\": 100000,\n        \"Devices\": [],\n        \"Dns\": null,\n        \"DnsOptions\": null,\n        \"DnsSearch\": null,\n        \"ExtraHosts\": null,\n        \"IpcMode\": \"\",\n        \"Links\": null,\n        \"LxcConf\": [],\n        \"Memory\": 0,\n        \"MemorySwap\": 0,\n        \"MemoryReservation\": 0,\n        \"KernelMemory\": 0,\n        \"OomKillDisable\": false,\n        \"OomScoreAdj\": 500,\n        \"NetworkMode\": \"bridge\",\n        \"PidMode\": \"\",\n        \"PortBindings\": {},\n        \"Privileged\": false,\n        \"ReadonlyRootfs\": false,\n        \"PublishAllPorts\": false,\n        \"RestartPolicy\": {\n            \"MaximumRetryCount\": 2,\n            \"Name\": \"on-failure\"\n        },\n        \"LogConfig\": {\n            \"Config\": null,\n            \"Type\": \"json-file\"\n        },\n        \"SecurityOpt\": null,\n        \"Sysctls\": {\n                \"net.ipv4.ip_forward\": \"1\"\n        },\n        \"StorageOpt\": null,\n        \"VolumesFrom\": null,\n        \"Ulimits\": [{}],\n        \"VolumeDriver\": \"\",\n        \"ShmSize\": 67108864\n    },\n    \"HostnamePath\": \"/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hostname\",\n    \"HostsPath\": \"/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hosts\",\n    \"LogPath\": \"/var/lib/docker/containers/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b-json.log\",\n    \"Id\": \"ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39\",\n    \"Image\": \"04c5d3b7b0656168630d3ba35d8889bd0e9caafcaeb3004d2bfbc47e7c5d35d2\",\n    \"MountLabel\": \"\",\n    \"Name\": \"/boring_euclid\",\n    \"NetworkSettings\": {\n        \"Bridge\": \"\",\n        \"SandboxID\": \"\",\n        \"HairpinMode\": false,\n        \"LinkLocalIPv6Address\": \"\",\n        \"LinkLocalIPv6PrefixLen\": 0,\n        \"Ports\": null,\n        \"SandboxKey\": \"\",\n        \"SecondaryIPAddresses\": null,\n        \"SecondaryIPv6Addresses\": null,\n        \"EndpointID\": \"\",\n        \"Gateway\": \"\",\n        \"GlobalIPv6Address\": \"\",\n        \"GlobalIPv6PrefixLen\": 0,\n        \"IPAddress\": \"\",\n        \"IPPrefixLen\": 0,\n        \"IPv6Gateway\": \"\",\n        \"MacAddress\": \"\",\n        \"Networks\": {\n            \"bridge\": {\n                \"NetworkID\": \"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812\",\n                \"EndpointID\": \"7587b82f0dada3656fda26588aee72630c6fab1536d36e394b2bfbcf898c971d\",\n                \"Gateway\": \"172.17.0.1\",\n                \"IPAddress\": \"172.17.0.2\",\n                \"IPPrefixLen\": 16,\n                \"IPv6Gateway\": \"\",\n                \"GlobalIPv6Address\": \"\",\n                \"GlobalIPv6PrefixLen\": 0,\n                \"MacAddress\": \"02:42:ac:12:00:02\"\n            }\n        }\n    },\n    \"Path\": \"/bin/sh\",\n    \"ProcessLabel\": \"\",\n    \"ResolvConfPath\": \"/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/resolv.conf\",\n    \"RestartCount\": 1,\n    \"State\": {\n        \"Error\": \"\",\n        \"ExitCode\": 9,\n        \"FinishedAt\": \"2015-01-06T15:47:32.080254511Z\",\n        \"OOMKilled\": false,\n        \"Dead\": false,\n        \"Paused\": false,\n        \"Pid\": 0,\n        \"Restarting\": false,\n        \"Running\": true,\n        \"StartedAt\": \"2015-01-06T15:47:32.072697474Z\",\n        \"Status\": \"running\"\n    },\n    \"Mounts\": [\n        {\n            \"Name\": \"fac362...80535\",\n            \"Source\": \"/data\",\n            \"Destination\": \"/data\",\n            \"Driver\": \"local\",\n            \"Mode\": \"ro,Z\",\n            \"RW\": false,\n            \"Propagation\": \"\"\n        }\n    ]\n}\n```\n\nIn DoMonit code the function that will reply with the name of the restart policy should have the following name:\n\n```\ndef host_config_restart_policy_name():\n    [...]\n    return [...]\n```\n\n- Functions name are in small letters and describes the \"path\" to follow in the json response to get it.\n- ```HostConfig``` should be named ```host_config``` and ```RestartPolicy``` should be named ```restart_policy``` which gives ```host_config_restart_policy_name```\n\n```\n    \"HostConfig\": {\n        \"\":\"\",\n        \"\":\"\",\n        \"\":\"\",\n\t[...]\n        \"RestartPolicy\": {\n            \"MaximumRetryCount\": 2,\n            \"Name\": \"on-failure\"\n        },\n        [...]\n    },\n```\n\n# How To Contribute\n- Submit a feature proposal if you have new features to add. If you fixing a bug, this step is optional\n- Fork the repo and then clone it to your development machine\n\n```\ngit clone https://github.com/eon01/DoMonit.git\n```\n- Create a new branch\n```\ngit checkout -b my-new-feature\n```\n- Add your code \n- Follow the code style and naming conventions\n- Write some documentations and tests\n- Commit your changes and push the new branch to your fork\n```\ngit add .\ngit commit -m 'Your detailed description'\n```\n\n- If the remote repos (the forked one) is not set, type:\n```\ngit remote set-url origin https://github.com/\u003cyour_username\u003e/DoMonit\n```\n- Push changes:\n\n```\ngit push origin my-new-feature\n```\n- Submit a pull request\n- You can get a list of your commits:\n```\ngit log --oneline origin/master..my-new-feature\n```\n- It is optional but if accepted and merged, you can delete your branch (remotly and locally)\n```\ngit checkout master\ngit push origin :my-new-feature\ngit branch -D my-new-feature\n```\n\n# ToDo\n- Documentation\n- Exception \u0026 timeout handling\n- Unit testing\n","funding_links":[],"categories":["Development with Docker","Python","Monitoring"],"sub_categories":["API Client"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feon01%2FDoMonit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feon01%2FDoMonit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feon01%2FDoMonit/lists"}