ToCode
Open in Telegram
1 419
Subscribers
No data24 hours
No data7 days
No data30 days
Posts Archive
1 419
# שלב 2
לפני כמה ימים סיפרתי פה איך שרבטטי בוט טלגרם בפייתון כדי להחליף את הבוט שהיה לנו באליקסיר, בגלל שהישן הפסיק לעבוד ועדכון כל התלויות של האליקסיר לא נראה לי שווה את ההשקעה. על הדרך מחקתי 90% מהקוד של הבוט.
ואז התחילו הבעיות:
1. הבוט החדש לא הצליח לפצל הודעות ארוכות כמו שצריך
2. הבוט החדש לא שלח הודעות Markdown אלא טקסט רגיל, ולכן דוגמאות הקוד הופיעו שבורות בערוץ.
מה שלא סיפרתי זה שבגלל לוחות הזמנים (הבוט הישן לא עבד, לא היה ברור איך לתקן אותו ורציתי בוט חדש מהר), גם דילגתי על כל הכללים של תהליך פיתוח תקין:
1. את הקוד כתבתי ישירות על שרת ה Production ב vi.
2. את הטוקן של טלגרם כתבתי Hard Coded בתוך הסקריפט.
3. על Source Control או בדיקות לא היה מה לדבר.
הרבה תוכניות קטנות מתחילות ככה, עם התפיסה שזה רק משהו זמני, קטן, שפותר עכשיו איזו בעיה דחופה ובעתיד כשיהיה זמן נסדר את זה. הרבה תוכניות קטנות גם נשארות במצב הזה, וגם הבוט שלי היה בקלות יכול להישאר באותו בור. כל מה שהיה צריך זה לתקן את הבאגים באותו vi ועל אותו שרת פרודקשן. כנראה שזה אפילו היה לוקח פחות זמן.
אבל על הנקודה הזאת שתוכנית כבר עובדת ועושה משהו עדיף להסתכל בתור הזדמנות. התיקון לא חייב לקרות באותו יום שהבעיות התגלו, אבל כשכבר יושבים לתקן שווה להשקיע עוד כמה שעות ולסדר את כל הדברים שדילגנו עליהם בגירסה הראשונה והמהירה:
1. להעביר את הקוד לגיט מסודר.
2. להוסיף בדיקות ל flows החשובים או לפחות לאלה שהיו שבורים.
3. לבנות מנגנון Deploy מסודר שישתמש ב CI (במקום להעתיק קבצים עם rsync).
4. להעביר החוצה סודות למשתני סביבה.
וזה בדיוק היה שלב 2 בפיתוח הבוט, שאולי חלקכם שמתם לב אליו בפירסומים והמחיקות שעשיתי במהלך אתמול. הקוד המעודכן של הבוט עלה לגיטהאב ואתם מוזמנים לקרוא אותו כאן:
https://github.com/ynonp/blog-to-telegram
תוספת ראשונה לקוד היא מבנה התיקיות, עם תיקיה אחת לתוכנית ותיקיה לבדיקות.
תוספת שניה לקוד היא הקובץ
.github/workflows שמעלה מכונה שמתקינה את כל התלויות ומריצה את התוכנית פעם ביום בשעה שמונה בבוקר. אני מקווה שהמעבר ל Github Action יגרום לסקריפט להיות יותר יציב ולא להישבר גם אם השרת עמוס או שודרג. זה ה Workflow:
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: publish-daily-post-to-telegram
on:
workflow_dispatch:
schedule:
- cron: "0 8 * * *"
permissions:
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: run
env:
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
run: |
python blog_to_telegram/publish_daily_post.py
המעבר לגיטהאב ול Workflow גם הכריח אותי להוציא את הסוד מהקובץ לתוך Secret של גיטהאב, וקידם אותי עוד צעד בדרך לקוד טוב יותר.
כמובן ששלב שני הוא לא סוף הדרך. נשאר עוד:
1. להוסיף Workflow שכל פעם שדוחפים קוד חדש יריץ אוטומטית את כל הבדיקות.
2. להוסיף בדיקות (כרגע יש רק בדיקות למנגנון פיצול ההודעות).
3. להוסיף קובץ Readme ותיעוד בתוך הקוד.
אבל זה יחכה לבאג הבא או ל Pull Request מכם. מה שיבוא קודם.1 419
נ.ב. בינתיים ה action רץ רק ידנית ולא דרך ה cron שמוגדר שם… אם למישהו/י יש רעיון למה אשמח לכל עזרה
1 419
# שלב 2
לפני כמה ימים סיפרתי פה איך שרבטטי בוט טלגרם בפייתון כדי להחליף את הבוט שהיה לנו באליקסיר, בגלל שהישן הפסיק לעבוד ועדכון כל התלויות של האליקסיר לא נראה לי שווה את ההשקעה. על הדרך מחקתי 90% מהקוד של הבוט.
ואז התחילו הבעיות:
1. הבוט החדש לא הצליח לפצל הודעות ארוכות כמו שצריך
2. הבוט החדש לא שלח הודעות Markdown אלא טקסט רגיל, ולכן דוגמאות הקוד הופיעו שבורות בערוץ.
מה שלא סיפרתי זה שבגלל לוחות הזמנים (הבוט הישן לא עבד, לא היה ברור איך לתקן אותו ורציתי בוט חדש מהר), גם דילגתי על כל הכללים של תהליך פיתוח תקין:
1. את הקוד כתבתי ישירות על שרת ה Production ב vi.
2. את הטוקן של טלגרם כתבתי Hard Coded בתוך הסקריפט.
3. על Source Control או בדיקות לא היה מה לדבר.
הרבה תוכניות קטנות מתחילות ככה, עם התפיסה שזה רק משהו זמני, קטן, שפותר עכשיו איזו בעיה דחופה ובעתיד כשיהיה זמן נסדר את זה. הרבה תוכניות קטנות גם נשארות במצב הזה, וגם הבוט שלי היה בקלות יכול להישאר באותו בור. כל מה שהיה צריך זה לתקן את הבאגים באותו vi ועל אותו שרת פרודקשן. כנראה שזה אפילו היה לוקח פחות זמן.
אבל על הנקודה הזאת שתוכנית כבר עובדת ועושה משהו עדיף להסתכל בתור הזדמנות. התיקון לא חייב לקרות באותו יום שהבעיות התגלו, אבל כשכבר יושבים לתקן שווה להשקיע עוד כמה שעות ולסדר את כל הדברים שדילגנו עליהם בגירסה הראשונה והמהירה:
1. להעביר את הקוד לגיט מסודר.
2. להוסיף בדיקות ל flows החשובים או לפחות לאלה שהיו שבורים.
3. לבנות מנגנון Deploy מסודר שישתמש ב CI (במקום להעתיק קבצים עם rsync).
4. להעביר החוצה סודות למשתני סביבה.
וזה בדיוק היה שלב 2 בפיתוח הבוט, שאולי חלקכם שמתם לב אליו בפירסומים והמחיקות שעשיתי במהלך אתמול. הקוד המעודכן של הבוט עלה לגיטהאב ואתם מוזמנים לקרוא אותו כאן:
https://github.com/ynonp/blog-to-telegram
תוספת ראשונה לקוד היא מבנה התיקיות, עם תיקיה אחת לתוכנית ותיקיה לבדיקות.
תוספת שניה לקוד היא הקובץ
.github/workflows שמעלה מכונה שמתקינה את כל התלויות ומריצה את התוכנית פעם ביום בשעה שמונה בבוקר. אני מקווה שהמעבר ל Github Action יגרום לסקריפט להיות יותר יציב ולא להישבר גם אם השרת עמוס או שודרג. זה ה Workflow:
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: publish-daily-post-to-telegram
on:
workflow_dispatch:
schedule:
- cron: "0 8 * * *"
permissions:
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: run
env:
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
run: |
python blog_to_telegram/publish_daily_post.py
המעבר לגיטהאב ול Workflow גם הכריח אותי להוציא את הסוד מהקובץ לתוך Secret של גיטהאב, וקידם אותי עוד צעד בדרך לקוד טוב יותר.
כמובן ששלב שני הוא לא סוף הדרך. נשאר עוד:
1. להוסיף Workflow שכל פעם שדוחפים קוד חדש יריץ אוטומטית את כל הבדיקות.
2. להוסיף בדיקות (כרגע יש רק בדיקות למנגנון פיצול ההודעות).
3. להוסיף קובץ Readme ותיעוד בתוך הקוד.
אבל זה יחכה לבאג הבא או ל Pull Request מכם. מה שיבוא קודם.1 419
# עלות חודשית
מתכנת ריילס, גם אם מאוד מוכשר, אבל שלא נגע בריילס 5 שנים, יתקשה למצוא בזה עבודה היום.
מתכנתת ווב, אפילו מאוד מוכשרת, שפעם אחרונה שכתבה קוד JavaScript היתה לפני חמש שנים ב jQuery, תתקשה למצוא עבודה היום.
איש אבטחת מידע שחזר מטיול בעולם של חמש שנים, הולך לגלות שלא רק שהוא לא זוכר הרבה פרטים טכניים על חיפוש בעיות אבטחה במערכות, גם המערכות עצמן השתנו ואותם פרטים טכניים כבר לא יעזרו לו.
ואותו דבר בכל תחום טכנולוגי שאני יכול לדמיין: מרגע שיצאנו מהמסלול נכנסים לפעולה שני כוחות ומשתפים נגדנו פעולה - מצד אחד כל יום שלא נוגעים במשהו אנחנו שוכחים איך לעשות את זה, ומצד שני התפתחויות טכנולוגיות שכל הזמן קורות הופכות את הידע שעוד היה לנו ללא רלוונטי.
עבור מפתחים שעברו הסבה לטכנולוגיה אחרת, ושמעדיפים לא לשכוח דברים שאנחנו כבר יודעים, כמעט תמיד משתלם להשקיע קצת זמן כל יום גם בכלים שהם לא הכלים המרכזיים של היום יום:
1. לכתוב סקריפטים קטנים בפייתון או ב bash, אפילו שאנחנו כותבים קוד ב Java.
2. להמשיך לעבוד בלינוקס על הלפטופ, אפילו שבמקום החדש מותר לעבוד גם ב Windows.
3. לבנות ממשקים או אפליקציות קטנות לדברים "שוליים" כמו ממשק שמראה למי בחברה יש יום הולדת החודש.
4. להשתתף בפעילויות של קבוצות אחרות בארגון, או לנסות לעזור לאנשים שעובדים עכשיו במשהו שאתם פעם הייתם טובים בו.
אז נכון אם לקחתם 5 שנים לטיול מסביב לעולם אין טעם להמשיך לשלם את העלות החודשית של שימור הידע; אבל אם אתם כבר פה ועדיין כותבים קוד, אולי שווה לשים את השעה ביום כדי להשאיר עוד דלת פתוחה ליום סגריר.
1 419
# שלוש דוגמאות לתיעוד טוב מפרויקטי קוד פתוח
הבעיה עם תיעוד היא פער הזמנים בין הרגע שמישהי כותבת אותו לרגע שמישהי צריכה אותו. זה גורם לאנשים לכתוב תיעוד גרוע (כי "מי בכלל יקרא את זה") ולאנשים אחרים לעשות טעויות כי דברים בסיסיים לא כתובים בתיעוד. כמובן שיש גם יוצאים מן הכלל - ולכן בשביל לקבל השראה הנה שלוש דוגמאות לתיעוד מוצלח מפרויקטי קוד פתוח ב Python ו JavaScript.
## תיעוד Redux
הפונקציה
bindActionCreators של רידאקס היא דרך קלה להפוך את ה Action Creators שלנו לקלים יותר לשימוש. הנה קוד התיעוד שלה מתוך הקובץ src/bindActionCreators.ts בפרויקט:
/**
* Turns an object whose values are action creators, into an object with the
* same keys, but with every function wrapped into a `dispatch` call so they
* may be invoked directly. This is just a convenience method, as you can call
* `store.dispatch(MyActionCreators.doSomething())` yourself just fine.
*
* For convenience, you can also pass an action creator as the first argument,
* and get a dispatch wrapped function in return.
*
* @param actionCreators An object whose values are action
* creator functions. One handy way to obtain it is to use ES6 `import * as`
* syntax. You may also pass a single function.
*
* @param dispatch The `dispatch` function available on your Redux
* store.
*
* @returns The object mimicking the original object, but with
* every action creator wrapped into the `dispatch` call. If you passed a
* function as `actionCreators`, the return value will also be a single
* function.
*/
export default function bindActionCreators<A, C extends ActionCreator<A>>(
קישור לקוד המקורי:
https://github.com/reduxjs/redux/blob/master/src/bindActionCreators.ts#L18
התיעוד מספר בדיוק מה הפונקציה עושה, איזה פרמטרים היא מקבלת ומה היא מחזירה, כולל על האפשרות להעביר רק פונקציה בודדת בתור פרמטר. בהסבר על הפרמטר הראשון הם אפילו מציעים טיפ לשימוש יעיל בפונקציה כשמסבירים מאיפה לקבל את האוביקט שהיא צריכה לקבל כפרמטר.
## תיעוד Requests
המודול requests בפייתון מספק ממשק נוח לפעולות רשת ומטפל באינסוף אתגרים שקשורים בתקשורת עם אתרים - לדוגמה ניהול עוגיות, ניהול מספר בקשות ברצף, שיתוף הגדרות בין בקשות רשת ועוד.
הנה הפונקציה merge_setting מתוך הקובץ requests/sessions.py:
def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
"""Determines appropriate setting for a given request, taking into account
the explicit setting on that request, and the setting in the session. If a
setting is a dictionary, they will be merged together using `dict_class`
"""
גם בלי לקרוא את הקוד אני מבין שהפונקציה צריכה לשלב מפתחות השמורים בשני מבני נתונים אותם היא מקבלת כפרמטרים, ושהיא מאפשרת לי לשלוט במנגנון השילוב אם יש קונפליקט בין השניים.
אותה פונקציה כוללת גם הערה חשובה בתוך הקוד:
# Remove keys that are set to None. Extract keys first to avoid altering
# the dictionary during iteration.
none_keys = [k for (k, v) in merged_setting.items() if v is None]
for key in none_keys:
del merged_setting[key]
קישור לקוד: https://github.com/psf/requests/blob/main/requests/sessions.py.
כשקוראים את הקוד אפשר לתהות למה צריך שתי לולאות בשביל למחוק מפתחות מהמילון - ובשביל זה בדיוק ההערה מעל הלולאה מסבירה לנו שהמטרה של הבלאגן היא למנוע מצב שאנחנו משנים מילון תוך כדי שרצים עליו בלולאה.
## תיעוד lodash
והנה דוגמה אחרונה מספריית lodash, שקריאה בתיעוד שלה היא תמיד חוויה משמחת:
/**
* Creates an object composed of keys generated from the results of running
* each element of `collection` thru `iteratee`. The corresponding value of
* each key is the number of times the key was returned by `iteratee`. The
* iteratee is invoked with one argument: (value).
*
* @since 0.5.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.1 419
```
* @param {Function} iteratee The iteratee to transform keys.
* @returns {Object} Returns the composed aggregate object.
* @example
*
* const users = [
* { 'user': 'barney', 'active': true },
* { 'user': 'betty', 'active': true },
* { 'user': 'fred', 'active': false }
* ]
*
* countBy(users, value => value.active);
* // => { 'true': 2, 'false': 1 }
*/
function countBy(collection, iteratee) {
```
פה לא רק שאנחנו מקבלים תיאור של מה הפונקציה עושה, אלא גם את סוג האוביקט שמותר להעביר לכל פרמטר של הפונקציה ודוגמת הפעלה עם פירוט ערך החזרה. אחרי קריאה של תיעוד כזה ברור לגמרי מה האפשרויות שלי לעבודה עם הפונקציה.
תיעוד טוב אולי לא מחליף קוד טוב, אבל הוא בהחלט עוזר לאנשים אחרים לעבוד עם הקוד ולהבין אותו טוב יותר. השקעה בתיעוד, כמו השקעה בשיפור ביצועים, אבטחה, ממשק משתמש ותהליכי עבודה מתקדמים, לא נראית משתלמת באותו רגע אבל תבטיח לכם קוד שיהיה קל לתחזק ולשפר אותו.
1 419
# שלוש דוגמאות לתיעוד טוב מפרויקטי קוד פתוח
הבעיה עם תיעוד היא פער הזמנים בין הרגע שמישהי כותבת אותו לרגע שמישהי צריכה אותו. זה גורם לאנשים לכתוב תיעוד גרוע (כי "מי בכלל יקרא את זה") ולאנשים אחרים לעשות טעויות כי דברים בסיסיים לא כתובים בתיעוד. כמובן שיש גם יוצאים מן הכלל - ולכן בשביל לקבל השראה הנה שלוש דוגמאות לתיעוד מוצלח מפרויקטי קוד פתוח ב Python ו JavaScript.
## תיעוד Redux
הפונקציה `bindActionCreators` של רידאקס היא דרך קלה להפוך את ה Action Creators שלנו לקלים יותר לשימוש. הנה קוד התיעוד שלה מתוך הקובץ `src/bindActionCreators.ts` בפרויקט:
```language-javascript
/**
* Turns an object whose values are action creators, into an object with the
* same keys, but with every function wrapped into a `dispatch` call so they
* may be invoked directly. This is just a convenience method, as you can call
* `store.dispatch(MyActionCreators.doSomething())` yourself just fine.
*
* For convenience, you can also pass an action creator as the first argument,
* and get a dispatch wrapped function in return.
*
* @param actionCreators An object whose values are action
* creator functions. One handy way to obtain it is to use ES6 `import * as`
* syntax. You may also pass a single function.
*
* @param dispatch The `dispatch` function available on your Redux
* store.
*
* @returns The object mimicking the original object, but with
* every action creator wrapped into the `dispatch` call. If you passed a
* function as `actionCreators`, the return value will also be a single
* function.
*/
export default function bindActionCreators<A, C extends ActionCreator<A>>(
```
קישור לקוד המקורי:
[https://github.com/reduxjs/redux/blob/master/src/bindActionCreators.ts#L18](https://github.com/reduxjs/redux/blob/master/src/bindActionCreators.ts#L18)
התיעוד מספר בדיוק מה הפונקציה עושה, איזה פרמטרים היא מקבלת ומה היא מחזירה, כולל על האפשרות להעביר רק פונקציה בודדת בתור פרמטר. בהסבר על הפרמטר הראשון הם אפילו מציעים טיפ לשימוש יעיל בפונקציה כשמסבירים מאיפה לקבל את האוביקט שהיא צריכה לקבל כפרמטר.
## תיעוד Requests
המודול requests בפייתון מספק ממשק נוח לפעולות רשת ומטפל באינסוף אתגרים שקשורים בתקשורת עם אתרים - לדוגמה ניהול עוגיות, ניהול מספר בקשות ברצף, שיתוף הגדרות בין בקשות רשת ועוד.
הנה הפונקציה `merge_setting` מתוך הקובץ `requests/sessions.py`:
```language-python
def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
"""Determines appropriate setting for a given request, taking into account
the explicit setting on that request, and the setting in the session. If a
setting is a dictionary, they will be merged together using `dict_class`
"""
```
גם בלי לקרוא את הקוד אני מבין שהפונקציה צריכה לשלב מפתחות השמורים בשני מבני נתונים אותם היא מקבלת כפרמטרים, ושהיא מאפשרת לי לשלוט במנגנון השילוב אם יש קונפליקט בין השניים.
אותה פונקציה כוללת גם הערה חשובה בתוך הקוד:
```language-python
# Remove keys that are set to None. Extract keys first to avoid altering
# the dictionary during iteration.
none_keys = [k for (k, v) in merged_setting.items() if v is None]
for key in none_keys:
del merged_setting[key]
```
קישור לקוד: [https://github.com/psf/requests/blob/main/requests/sessions.py](https://github.com/psf/requests/blob/main/requests/sessions.py).
כשקוראים את הקוד אפשר לתהות למה צריך שתי לולאות בשביל למחוק מפתחות מהמילון - ובשביל זה בדיוק ההערה מעל הלולאה מסבירה לנו שהמטרה של הבלאגן היא למנוע מצב שאנחנו משנים מילון תוך כדי שרצים עליו בלולאה.
## תיעוד lodash
והנה דוגמה אחרונה מספריית lodash, שקריאה בתיעוד שלה היא תמיד חוויה משמחת:
```language-javascript
/**
* Creates an object composed of keys generated from the results of running
* each element of `collection` thru `iteratee`. The corresponding value of
* each key is the number of times the key was returned by `iteratee`. The
* iteratee is invoked with one argument: (value).
*
* @since 0.5.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
```
1 419
# עלות חודשית
מתכנת ריילס, גם אם מאוד מוכשר, אבל שלא נגע בריילס 5 שנים, יתקשה למצוא בזה עבודה היום.
מתכנתת ווב, אפילו מאוד מוכשרת, שפעם אחרונה שכתבה קוד JavaScript היתה לפני חמש שנים ב jQuery, תתקשה למצוא עבודה היום.
איש אבטחת מידע שחזר מטיול בעולם של חמש שנים, הולך לגלות שלא רק שהוא לא זוכר הרבה פרטים טכניים על חיפוש בעיות אבטחה במערכות, גם המערכות עצמן השתנו ואותם פרטים טכניים כבר לא יעזרו לו.
ואותו דבר בכל תחום טכנולוגי שאני יכול לדמיין: מרגע שיצאנו מהמסלול נכנסים לפעולה שני כוחות ומשתפים נגדנו פעולה - מצד אחד כל יום שלא נוגעים במשהו אנחנו שוכחים איך לעשות את זה, ומצד שני התפתחויות טכנולוגיות שכל הזמן קורות הופכות את הידע שעוד היה לנו ללא רלוונטי.
עבור מפתחים שעברו הסבה לטכנולוגיה אחרת, ושמעדיפים לא לשכוח דברים שאנחנו כבר יודעים, כמעט תמיד משתלם להשקיע קצת זמן כל יום גם בכלים שהם לא הכלים המרכזיים של היום יום:
1. לכתוב סקריפטים קטנים בפייתון או ב bash, אפילו שאנחנו כותבים קוד ב Java.
2. להמשיך לעבוד בלינוקס על הלפטופ, אפילו שבמקום החדש מותר לעבוד גם ב Windows.
3. לבנות ממשקים או אפליקציות קטנות לדברים "שוליים" כמו ממשק שמראה למי בחברה יש יום הולדת החודש.
4. להשתתף בפעילויות של קבוצות אחרות בארגון, או לנסות לעזור לאנשים שעובדים עכשיו במשהו שאתם פעם הייתם טובים בו.
אז נכון אם לקחתם 5 שנים לטיול מסביב לעולם אין טעם להמשיך לשלם את העלות החודשית של שימור הידע; אבל אם אתם כבר פה ועדיין כותבים קוד, אולי שווה לשים את השעה ביום כדי להשאיר עוד דלת פתוחה ליום סגריר
1 419
יהיו 644 למשתמש וקבוצה root.
מבט בתיקיה מראה לי את הלוגים והרוטציות:
```language-sh
# ls -l /var/log/dpkg.log*
-rw-r--r-- 1 root root 7010 Aug 3 06:14 /var/log/dpkg.log
-rw-r--r-- 1 root root 50427 Jul 30 13:44 /var/log/dpkg.log.1
-rw-r--r-- 1 root root 5053 Jun 30 08:36 /var/log/dpkg.log.2.gz
-rw-r--r-- 1 root root 4512 May 28 06:14 /var/log/dpkg.log.3.gz
-rw-r--r-- 1 root root 8898 Apr 30 06:05 /var/log/dpkg.log.4.gz
-rw-r--r-- 1 root root 979 Mar 2 15:38 /var/log/dpkg.log.5.gz
-rw-r--r-- 1 root root 5376 Feb 25 10:52 /var/log/dpkg.log.6.gz
-rw-r--r-- 1 root root 4158 Jan 28 2022 /var/log/dpkg.log.7.gz
-rw-r--r-- 1 root root 2966 Dec 22 2021 /var/log/dpkg.log.8.gz
-rw-r--r-- 1 root root 55022 Nov 28 2021 /var/log/dpkg.log.9.gz
```
אנחנו רואים איך הלוג התקדם כל חודש, את הלוגים המכווצים ואת הלוג עם סיומת `.1` שעדיין לא כווץ.
## יצירת קונפיגורציה ללוגים שלי
בשביל להוסיף תוכנית שלי להגדרות logrotate אני בסך הכל צריך להוסיף עוד קובץ לתיקיית ה include. לדוגמה נניח שיש לי שרת ווב שמגיש אפליקציה בשם `mysite` וכותב הרבה לוגים בכל מיני שמות לתיקיית `/var/log/mysite/`. אני יכול להוסיף את הקובץ `/etc/logrotate.d/mysite` ובתוכו לכתוב את התוכן הבא:
```language-sh
/var/log/your-app/*.log {
daily
missingok
rotate 14
compress
notifempty
create 0640 www-data www-data
sharedscripts
postrotate
systemctl reload your-app
endscript
}
```
נתרגם:
1. רוטציית לוגים מבוצעת כל יום, ולוגים נשמרים 14 רוטציות, כלומר שבועיים.
2. לוגים ישנים מכווצים.
3. לא נורא אם אין לוגים.
4. לא נוגעים בקבצים ריקים.
5. הלוגים נוצרים תחת משתמש www-data.
6. הפקודות `postrotate` ו `sharedscripts` אומרות שאחרי שעשינוי רוטציה לכל הלוגים נריץ את הפקודה שכתובה ב postrotate, כלומר טעינה מחדש של השרת. זה נועד להתמודד עם זה ששרת ממשיך לכתוב לקובץ לוג אפילו אחרי שנמחק כי הוא החזיק את הקובץ פתוח. הסקריפט מסתיים בפקודה `endscript`.
רוצים ללמוד עוד על logrotate ואפשרויות השימוש בו? שווה לבקר בדף העזרה של דיגיטל אושן על הכלי (משם גם לקחתי את הדוגמה האחרונה בפוסט):
[https://www.digitalocean.com/community/tutorials/how-to-manage-logfiles-with-logrotate-on-ubuntu-20-04](https://www.digitalocean.com/community/tutorials/how-to-manage-logfiles-with-logrotate-on-ubuntu-20-04)
וכמובן ב man page של logrotate עצמה בקישור:
[https://www.man7.org/linux/man-pages/man8/logrotate.8.html](https://www.man7.org/linux/man-pages/man8/logrotate.8.html
1 419
# מדריך logrotate
לוג רוטייט הוא כלי אוטומטי שמכווץ קבצי לוג ישנים ומוחק אותם כשהם ממש ישנים. לוג רוטייט הוא אחד הכלים החשובים בעבודה על מכונות לינוקס כי בלעדיו קבצי הלוג יכולים להגיע לנפח עצום ולמלא את כל השרת. במדריך זה אסביר איך הוא עובד ואיך להוסיף קבצים שלכם לניקוי באמצעות logrotate.
## התקנה ובדיקת סטטוס
משורת הפקודה, אפילו בתור משתמש רגיל, אפשר להפעיל:
```language-sh
$ logrotate --version
```
כדי לראות אם הכלי מותקן אצלכם (מותקן ב Ubuntu אוטומטית, אז כנראה שכן). אם לא מותקן אפשר להתקין אותו עם:
```language-sh
$ sudo apt install logrotate
```
אני משתמש בגירסה 3.14.0.
בשביל לעבוד logrotate צריך לקבל קובץ הגדרות. הפעלה שלו בלי קובץ הגדרות מציגה פיסקת עזרה קצרה:
```language-sh
logrotate 3.14.0 - Copyright (C) 1995-2001 Red Hat, Inc.
This may be freely redistributed under the terms of the GNU General Public License
Usage: logrotate [-dfv?] [-d|--debug] [-f|--force] [-m|--mail=command] [-s|--state=statefile] [-v|--verbose] [-l|--log=logfile] [--version]
[-?|--help] [--usage] [OPTION...] <configfile>
```
קובץ ההגדרות הוא המפתח להצלחה ובו נספר ל logrotate מיהם קבצי הלוג שלנו, מתי לכווץ אותם ומתי למחוק אותם.
לוגרוטייט מופעל אוטומטית מתוך Cron Job יומי. אני יכול למצוא את פרטי הג'וב בקובץ `/etc/cron.daily/logrotate`. ככה זה נראה במכונה שלי:
```language-sh
$ cat /etc/cron.daily/logrotate
#!/bin/sh
# skip in favour of systemd timer
if [ -d /run/systemd/system ]; then
exit 0
fi
# this cronjob persists removals (but not purges)
if [ ! -x /usr/sbin/logrotate ]; then
exit 0
fi
/usr/sbin/logrotate /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit $EXITVALUE
```
## הגדרת לוגים
קובץ ההגדרות שמופעל בברירת מחדל הוא `/etc/logrotate.conf`. נכנס לראות מה כתוב בו:
```language-sh
# see "man logrotate" for details
# rotate log files weekly
weekly
# use the adm group by default, since this is the owning group
# of /var/log/syslog.
su root adm
# keep 4 weeks worth of backlogs
rotate 4
# create new (empty) log files after rotating old ones
create
# use date as a suffix of the rotated file
#dateext
# uncomment this if you want your log files compressed
#compress
# packages drop log rotation information into this directory
include /etc/logrotate.d
# system-specific logs may be also be configured here.
```
הנה עיקרי הדברים בתרגום:
1. המילה weekly אומרת שאנחנו מקדמים את הלוגים פעם בשבוע ביום ראשון. אפשר לציין את היום אם נכתוב מספר אחרי המילה weekly.
2. את הפעולה יבצע משתמש root בקבוצת adm.
3. הפקודה `rotate 4` אומרת שיהיו 4 סבבים של "שמירת לוג" לפני שמוחקים אותו, כלומר לוגים יישמרו ל 4 שבועות. כל שבוע לשם הקובץ יתווסף מספר שעולה ב-1 כל סיבוב.
4. אחרי סיבוב באופן אוטומטי יוצרים קובץ לוג חדש בשם המקורי.
5. המילה compress היא בהערה לכן ברירת המחדל אצלי על המכונה היא לא לכווץ לוגים.
6. הגדרות נוספות לפי סרביסים אפשר למצוא בתיקיית `/etc/logrotate.d`.
בעצם אנחנו רואים כאן שמבנה קובץ ההגדרות מתאים לזה שכל תוכנית שאני מתקין צריכה להוסיף את ההגדרות שלה לתיקיית `/etc/logrotate.d` ואז logrotate יעשה את הקסם שלו וינקה את הלוגים של אותה התוכנית.
על אותה מכונת אובונטו בתיקיית `/etc/logrotate.d` אני מוצא את קבצי ההגדרות הבאים:
```language-sh
# ls
alternatives btmp rsyslog unattended-upgrades
apport cups-daemon speech-dispatcher wtmp
apt dpkg ubuntu-advantage-tools
bootlog ppp ufw
```
נפתח אחד מהם בשביל לראות איך לכתוב הגדרות לסרביס:
```language-sh
# cat /etc/logrotate.d/dpkg
/var/log/dpkg.log {
monthly
rotate 12
compress
delaycompress
missingok
notifempty
create 644 root root
}
```
הסרביס dpkg שומר לוגים אחרת מברירת המחדל:
1. הוא מגדיר מהו קובץ הלוג שלו.
2. הרוטציה קורית פעם בחודש, ולוגים ישנים נשמרים 12 רוטציות, כלומר לשנה.
3. לוגים ישנים מכווצים.
4. הכיווץ לא קורה מיד אלא רק ברוטציה הבאה (נועד להתמודד עם תוכניות שמשאירות קובץ לוג פתוח וממשיכות לכתוב אליו גם אחרי ששינו לו את השם).
5. לא צריך לעשות עניינים אם הקובץ חסר.
6. לא לכווץ או להזיז אם הקובץ ריק
7. כשיוצרים קובץ חדש ההרשאות
Available now! Telegram Research 2025 — the year's key insights 
