# [[Recommended practices for using LogQL]] ![[Recommended practices for using LogQL.svg]] Below are some tips for running [[Grafana Loki|Loki]] [[LogQL]] queries. [^querybp] ## Narrow down the time range Before you even begin to write a query, consider selecting a smaller time range within the time range picker in Grafana. This reduces the amount of logs Loki will need to parse through. ## Use the right label selector Choose a label selector that is as unique as possible while still being relevant. Using a key-pair value that is present in all logs does not narrow down the results at all. Consider the [best practices for labels](https://gra.fan/lokilabelbp). ## Respect the left to right rule Remember that LogQL queries are executed from left to right. Write queries so that the least expensive operations that filter out the most amount of data are written on the left. Then work your way towards the most expensive operations that filter out the least amount of data as you work through to the right. When in doubt, narrow down your log results by progressing down this list: - line/label filters - parsers - formatters line/label filters are much less expensive than complex parsers like the regular expression parser. ## Discard results that match a filter Since Loki accepts unstructured logs, you may get logs that are not in the same format. When querying, you may not need Loki to parse logs that are not in a certain format. You can tell Loki to ignore lines that have a certain word like this: ``` __error__ ``` In this example, Loki would ignore logs with the word `error` and not return them in the results. This saves Loki some processing time. This feature is also particularly useful for discarding logs with invalid JSON. ## Test your queries To make sure your queries are functional, performant, and cost-effective, test and benchmark them regularly. ### LogQL simulator You can use the [LogQL Simulator](https://gra.fan/lokisimulator) to test out whether your queries work the way you expect without needing to have any of the Loki stack installed. It's an online app that just lets you paste a few lines of a sample log and then runs a LogQL query against them. ### k6 You can use the performance testing tool [[k6 (tool)|k6]] to both send to (write) or query (read) logs to Loki using the [[Extensions for k6 using xk6|extension]] [[xk6-loki]]. ### [[LogCLI]] ### Query the entire data set A simple way to test your query for performance is to run a query and then run the opposite query. For example: ``` {service_name=`nginx-json`} |= “foo” != “foo” ``` This query uses a line filter on both all logs that contain `foo` *and* all logs that *don't* contain `foo`, thus searching the entire data set. You can then have a look at the time the query took to display results, which is always shown within Grafana when you run a query. ### Query Loki's meta-logs Loki keeps meta-logs of every LogQL query in `metrics.go`. You can query this by using `metrics.go` in a line filter expression like this: ``` {namespace=“loki-dev-005”,container=“query-frontend”} |= “metrics.go” | logfmt | duration > 10s ``` `metrics.go` returns information you can use to assess a query's performance, such as: - **total_bytes**: how many total bytes the query processed - **duration**: how long the query took to execute - **throughput**: total_bytes/duration - **total_lines**: how many total lines the query processed - **length**: how much time the query was executed over - **post_filter_lines**: how many lines matched the filters in the query - **cache_chunk_req**: total number of chunks fetched for the query (the cache will be asked for every chunk so this is equivalent to the total chunks requested) - **splits**: how many pieces the query was split into based on time and split_queries_by_interval - **shards**: how many shards the query was split into [^querybp]: Grafana Labs. Query best practices. Retrieved from https://gra.fan/lokiquerybp %% # Excalidraw Data ## Text Elements ## Drawing ```json { "type": "excalidraw", "version": 2, "source": "https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/2.1.4", "elements": [ { "id": "4y8R7iOA", "type": "text", "x": 118.49495565891266, "y": -333.44393157958984, "width": 3.8599853515625, "height": 24, "angle": 0, "strokeColor": "#1e1e1e", "backgroundColor": "transparent", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "groupIds": [], "frameId": null, "roundness": null, "seed": 967149026, "version": 2, "versionNonce": 939059582, "isDeleted": true, "boundElements": null, "updated": 1713723615080, "link": null, "locked": false, "text": "", "rawText": "", "fontSize": 20, "fontFamily": 4, "textAlign": "left", "verticalAlign": "top", "containerId": null, "originalText": "", "lineHeight": 1.2 } ], "appState": { "theme": "dark", "viewBackgroundColor": "#ffffff", "currentItemStrokeColor": "#1e1e1e", "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "solid", "currentItemStrokeWidth": 2, "currentItemStrokeStyle": "solid", "currentItemRoughness": 1, "currentItemOpacity": 100, "currentItemFontFamily": 4, "currentItemFontSize": 20, "currentItemTextAlign": "left", "currentItemStartArrowhead": null, "currentItemEndArrowhead": "arrow", "scrollX": 583.2388916015625, "scrollY": 573.6323852539062, "zoom": { "value": 1 }, "currentItemRoundness": "round", "gridSize": null, "gridColor": { "Bold": "#C9C9C9FF", "Regular": "#EDEDEDFF" }, "currentStrokeOptions": null, "previousGridSize": null, "frameRendering": { "enabled": true, "clip": true, "name": true, "outline": true } }, "files": {} } ``` %%