JavaRush /בלוג Java /Random-HE /כניסה ל-Java: מה, איך, איפה ועם מה?
Roman Beekeeper
רָמָה

כניסה ל-Java: מה, איך, איפה ועם מה?

פורסם בקבוצה
שלום לכולם, קהילת JavaRush! היום נדבר על רישום ג'אווה:
  1. מה זה, למה זה. באילו מקרים עדיף להשתמש, באילו מקרים לא?
  2. אילו סוגי יישומי רישום יש בג'אווה ומה עלינו לעשות עם הגיוון הזה?
  3. רמות רישום. בואו נדון מהו תוספת וכיצד להגדיר אותו בצורה נכונה.
  4. רישום צמתים וכיצד להגדיר אותם בצורה נכונה כך שהכל יעבוד כמו שאנחנו רוצים.
חומר זה מיועד לקהל רחב. זה יהיה ברור גם למי שרק מכיר את ג'אווה וגם למי שכבר עובד, אבל רק הבין את זה עם logger.info(“log something”); Let's Go!

מדוע יש צורך ברישום?

בואו נסתכל על מקרים אמיתיים שבהם רישום יפתור את הבעיה. הנה דוגמה מהעבודה שלי. ישנן נקודות יישום המשתלבות עם שירותים אחרים. אני משתמש ברישום של נקודות אלה כ"אליבי" : אם האינטגרציה לא עובדת, יהיה קל להבין מאיזה צד הבעיה נובעת. כמו כן, רצוי לרשום מידע חשוב שנשמר במסד הנתונים. לדוגמה, יצירת משתמש מנהל. זה בדיוק מה שיהיה טוב לרשום.

כלי רישום של Java

רישום: מה, איך, איפה ועם מה?  - 2פתרונות ידועים לכניסה ל-Java כוללים:
  • log4j
  • JUL - java.util.logging
  • JCL - רישום קומות ג'קרטה
  • התחבר חזרה
  • SLF4J - חזית רישום פשוטה עבור ג'אווה
בואו נסתכל במהירות על כל אחד מהם, ובחלק המעשי של החומר ניקח את החיבור Slf4j - log4j כבסיס . זה אולי נראה מוזר עכשיו, אבל אל דאגה: בסוף המאמר הכל יהיה ברור.

System.err.println

בתחילה, כמובן, היה System.err.println (פלט שיא לקונסולה). זה עדיין משמש כדי להשיג במהירות יומן במהלך איתור באגים. כמובן, אין צורך לדבר על הגדרות כלשהן כאן, אז בואו פשוט נזכור את זה ונמשיך הלאה.

Log4j

זה כבר היה פתרון מלא, שנוצר מצרכים של מפתחים. התברר שזה כלי ממש מעניין לשימוש. בשל נסיבות שונות, הפתרון הזה מעולם לא נכנס ל-JDK, מה שהרגיז מאוד את הקהילה כולה. ל-log4j היו אפשרויות תצורה כך שניתן היה להפעיל רישום בחבילה com.example.typeולכבות בחבילת משנה com.example.type.generic. זה איפשר להפריד במהירות בין מה שצריך לרשום ממה שלא נחוץ. חשוב לציין כאן שיש שתי גרסאות של log4j: 1.2.x ו-2.x.x, שאינן תואמות זו לזו . log4j הוסיף מושג כזה כמו appender , כלומר, כלי שבעזרתו נרשמים יומנים ופריסה - עיצוב יומן. זה מאפשר לך להקליט רק את מה שאתה צריך ואיך אתה צריך את זה. נדבר יותר על תוספתן מעט מאוחר יותר.

JUL - java.util.logging

אחד היתרונות המרכזיים הוא הפתרון - JUL כלול ב-JDK (ערכת פיתוח Java). למרבה הצער, במהלך הפיתוח שלו לא היה זה ה-log4j הפופולרי שנלקח כבסיס, אלא פתרון מבית IBM, שהשפיע על פיתוחו. למעשה, כרגע יש JUL, אבל אף אחד לא משתמש בו. מה"ככה": ב-JUL רמות הרישום שונות ממה שיש ב-Logback, Log4j, Slf4j, וזה מחמיר את ההבנה ביניהם. יצירת לוגר דומה פחות או יותר. לשם כך עליך לייבא:
java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
שם הכיתה מועבר במיוחד כדי לדעת מאיפה מגיע הרישום. מאז Java 8, אפשר לעבור Supplier<String>. זה עוזר לספור וליצור מחרוזת רק ברגע שבו באמת צריך, ולא בכל פעם, כפי שהיה קודם. רק עם שחרורו של Java 8 מפתחים פתרו בעיות חשובות, ולאחר מכן JUL באמת הפך שמיש. כלומר, שיטות עם ארגומנט Supplier<String> msgSupplierכפי שמוצג להלן:
public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL - רישום קומות ג'קרטה

בשל העובדה שבמשך זמן רב לא היה סטנדרט תעשייתי ברישום והייתה תקופה שבה אנשים רבים יצרו לוגר מותאם אישית משלהם, הם החליטו לשחרר את JCL - עטיפה נפוצה שתשמש על פני אחרים. למה? כאשר התווספו כמה תלות לפרוייקט, הם יכלו להשתמש ב-logger שונה מה-logger בפרויקט. בגלל זה, הם נוספו באופן טרנזיטיבי לפרויקט, מה שיצר בעיות של ממש כשניסו לחבר את הכל ביחד. לרוע המזל, העטיפה הייתה ירודה מאוד בפונקציונליות ולא הציגה תוספות. זה כנראה יהיה נוח אם כולם ישתמשו ב-JCL כדי לעשות את העבודה שלהם. אבל במציאות זה לא עבד כך, אז השימוש ב-JCL הוא לא רעיון טוב כרגע.

התחבר חזרה

כמה קוצני היא הדרך של קוד פתוח... Logback נכתב על ידי אותו מפתח כמו log4j כדי ליצור יורש שלו. הרעיון היה זהה ל-log4j. ההבדלים היו ב-Logback:
  • ביצועים משופרים;
  • נוספה תמיכה מקורית עבור slf4j;
  • אפשרות הסינון הורחבה.
כברירת מחדל, כניסה לאחור אינה דורשת הגדרות כלשהן ומתעדת את כל היומנים מרמת DEBUG ומעלה. אם יש צורך בהגדרה, ניתן לעשות זאת באמצעות תצורת xml:
<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>app.log</file>
        <encoder>
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" />
    <root level="info">
        <appender-ref ref="FILE" />
    </root>
</configuration>

SLF4J - חזית רישום פשוטה עבור ג'אווה

בסביבות 2006, אחד מהאבות המייסדים של log4j עזב את הפרויקט ויצר את slf4j - Simple Logging Facade for Java - עוטף סביב log4j, JUL, common-logins ו-logback. כפי שניתן לראות, ההתקדמות הגיעה למצב שיצרו עטיפה על גבי העטיפה... יתרה מכך, היא מתחלקת לשני חלקים: ה-API, המשמש באפליקציה, והיישום, שמתווסף כ- תלות נפרדת עבור כל סוג רישום. לדוגמה, slf4j-log4j12.jar, slf4j-jdk14.jar. מספיק לחבר את היישום הנכון וזהו: כל הפרויקט יעבוד איתו. Slf4j תומך בכל התכונות החדשות כגון עיצוב מחרוזת לרישום. הייתה בעיה כזו בעבר. נניח שיש ערך ביומן:
log.debug("User " + user + " connected from " + request.getRemoteAddr());
userיש המרה מרומזת באובייקט user.toString()עקב שרשרת מחרוזת, וזה לוקח זמן, מה שמאט את המערכת. והכל בסדר אם ננקה באגים באפליקציה. הבעיות מתחילות אם רמת הרישום עבור מחלקה זו היא INFO ומעלה. כלומר, אין לרשום את היומן הזה, וגם אין לבצע שרשור מחרוזות. בתיאוריה, ספריית הרישום עצמה הייתה צריכה להחליט על כך. יתר על כן, זו התבררה כבעיה הגדולה ביותר של הגרסה הראשונה של log4j. הם לא סיפקו פתרון נורמלי, אבל הציעו לעשות זאת כך:
if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
כלומר, במקום שורת רישום אחת, הציעו לכתוב 3(!). רישום צריך למזער שינויים בקוד, ושלוש שורות סתרו בבירור את הגישה הכללית. ל-slf4j לא היו בעיות תאימות עם ה-JDK וה-API, אז מיד הופיע פתרון יפה:
log.debug("User {} connected from {}", user, request.getRemoteAddr());
כאשר {}מציינים הוספת ארגומנטים המועברים בשיטה. כלומר, הראשון {}מתאים ל user, השני {}- request.getRemoteAddr(). בשל כך, רק אם רמת הרישום מאפשרת הקלטה ליומן, ניתן לשרשר הודעה זו להודעה אחת. לאחר מכן, SJF4J גדל במהירות בפופולריות והוא כרגע הפתרון הטוב ביותר. לכן, נשקול רישום באמצעות הדוגמה של חבילה slf4j-log4j12.

מה צריך לרשום

כמובן, אתה לא צריך לרשום הכל. לפעמים זה מיותר ואפילו מסוכן. לדוגמה, אם אתה מתחייב לנתונים אישיים של מישהו וזה איכשהו יתגלה, יהיו בעיות אמיתיות, במיוחד בפרויקטים המכוונים למערב. אבל יש גם משהו שחובה להתחבר :
  1. התחלה/סיום של האפליקציה. עלינו לדעת שהאפליקציה למעשה הושקה כפי שציפינו והסתיימה כצפוי.
  2. שאלות אבטחה. כאן זה יהיה טוב לרשום ניסיונות ניחוש סיסמאות, התחברויות של משתמשים חשובים וכו'.
  3. חלק ממדינות היישום . למשל, המעבר ממדינה אחת לאחרת בתהליך עסקי.
  4. קצת מידע לניפוי באגים , עם רמת רישום מתאימה.
  5. כמה סקריפטים של SQL. יש מקרים אמיתיים שבהם יש צורך בכך. שוב, על ידי התאמת הרמות במיומנות, ניתן להגיע לתוצאות מצוינות.
  6. ניתן לרשום שרשורים מבוצעים (Thread) במקרים בהם נבדקת הפעולה הנכונה.

טעויות רישום פופולריות

ישנם ניואנסים רבים, אך הנה כמה טעויות נפוצות:
  1. רישום עודף. אתה לא צריך לרשום כל שלב שיכול תיאורטית להיות חשוב. יש כלל: יומנים יכולים לטעון את הביצועים בשיעור של לא יותר מ-10%. אחרת יהיו בעיות ביצועים.
  2. רישום כל הנתונים לקובץ אחד. זה יקשה מאוד על קריאה/כתיבה בשלב מסוים, שלא לדבר על הגבלות על גודל קבצים במערכות מסוימות.
  3. שימוש ברמות רישום שגויות. לכל רמת רישום יש גבולות ברורים ויש לכבד אותה. אם הגבול מעורפל, אתה יכול להסכים באיזו רמה להשתמש.

רמות רישום

x: גלוי
קָטלָנִי שְׁגִיאָה לְהַזהִיר מידע לנפות זֵכֶר את כל
כבוי
קָטלָנִי איקס
שְׁגִיאָה איקס איקס
לְהַזהִיר איקס איקס איקס
מידע איקס איקס איקס איקס
לנפות איקס איקס איקס איקס איקס
זֵכֶר איקס איקס איקס איקס איקס איקס
את כל איקס איקס איקס איקס איקס איקס איקס
מהן רמות רישום? כדי לדרג איכשהו את היומנים, היה צורך לתת ייעודים והבחנות מסוימות. לשם כך הוכנסו רמות רישום. הרמה מוגדרת באפליקציה. אם ערך שייך לרמה מתחת לרמה המיועדת, הוא לא מוזן ביומן. לדוגמה, יש לנו יומנים המשמשים לניפוי באגים באפליקציה. בעבודת ייצור רגילה (כאשר האפליקציה משמשת למטרה המיועדת לה), אין צורך ביומנים כאלה. לכן, רמת הרישום תהיה גבוהה יותר מאשר עבור ניפוי באגים. בואו נסתכל על רמות באמצעות log4j כדוגמה. פתרונות אחרים, מלבד JUL, משתמשים באותן רמות. הנה הם בסדר יורד:
  • כבוי: לא נכתבים יומנים, כולם יתעלמו;
  • FATAL: שגיאה שלאחריה האפליקציה לא תוכל לעבוד יותר ותיעצר, למשל, שגיאת JVM out of memory;
  • שגיאה: שיעור השגיאות כאשר יש בעיות שצריך לפתור. השגיאה אינה עוצרת את היישום בכללותו. שאילתות אחרות עשויות לפעול כהלכה;
  • אזהרה: מציין יומנים המכילים אזהרה. התרחשה פעולה בלתי צפויה, למרות זאת המערכת התנגדה והשלימה את הבקשה;
  • INFO: יומן שמתעד פעולות חשובות באפליקציה. אלו אינן שגיאות, אלו אינן אזהרות, אלו פעולות צפויות של המערכת;
  • DEBUG: יומנים הדרושים לניפוי באגים באפליקציה. לוודא שהמערכת עושה בדיוק את מה שמצופה ממנה, או לתאר את פעולת המערכת: "שיטה 1 התחילה לעבוד";
  • TRACE: יומנים בעדיפות נמוכה יותר עבור ניפוי באגים, עם רמת הרישום הנמוכה ביותר;
  • ALL: רמה שבה יתועדו כל היומנים מהמערכת.
מסתבר שאם רמת רישום ה-INFO מופעלת במקום כלשהו באפליקציה, כל הרמות יירשמו, החל מ-INFO ועד FATAL. אם רמת הרישום היא FATAL, רק יומנים עם רמה זו יתועדו.

הקלטה ושליחה של יומנים: Appender

נשקול תהליך זה באמצעות log4j כדוגמה: הוא מספק הזדמנויות רבות להקלטה/שליחת יומנים:
  • לכתיבה לקובץ-פתרון DailyRollingFileAppender ;
  • כדי לקבל נתונים לתוך מסוף היישומים - ConsoleAppender ;
  • לכתוב יומנים למסד הנתונים - JDBCAppender ;
  • לשלוט בשידור באמצעות TCP/IP - TelnetAppender ;
  • כדי להבטיח שהרישום לא ישפיע על הביצועים - AsyncAppender .
יש עוד כמה יישומים: את הרשימה המלאה ניתן למצוא כאן . אגב, אם הנספח הנדרש אינו זמין, זו לא בעיה. אתה יכול לכתוב תוספת משלך על ידי הטמעת ממשק ה-Appender , שמקבל רק log4j.

רישום צמתים

לצורך ההדגמה נשתמש בממשק slf4j, וביישום מ-log4j. יצירת לוגר היא פשוטה מאוד: אתה צריך לכתוב את הדברים הבאים במחלקה בשם MainDemo, שבה יתבצע רישום:
org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
זה יצור עבורנו לוגר. כדי לבצע רישום ביומן, ניתן להשתמש בשיטות רבות המציינות באיזו רמה הכניסות יבוצעו. לדוגמה:
logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find log4j.properties. Please, provide them");
logger.error("Connection refused to host = {}", host);
למרות שאנחנו עוברים את הכיתה, בסופו של דבר זה השם המלא של הכיתה עם חבילות שכתוב. זה נעשה כדי שבהמשך תוכל לחלק את הרישום לצמתים, ולהגדיר רמת רישום ותוספת עבור כל צומת. לדוגמה, שם המחלקה: com.github.romankh3.logginglecture.MainDemo- נוצר בה לוגר. וכך ניתן לחלק אותו לצמתי רישום. הצומת הראשי הוא ה- RootLogger null . זהו הצומת שמקבל את כל היומנים של האפליקציה כולה. ניתן לתאר את השאר כפי שמוצג להלן: רישום: מה, איך, איפה ועם מה?  - 4נספחים מגדירים את עבודתם באופן ספציפי על צמתי רישום. כעת, באמצעות log4j.properties כדוגמה , נבחן כיצד להגדיר אותם.

שלב אחר שלב תצורה של Log4j.properties

כעת נגדיר הכל צעד אחר צעד ונראה מה ניתן לעשות:
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
שורה זו אומרת שאנו רושמים תוספת CONSOLE שמשתמשת ביישום org.apache.log4j.ConsoleAppender. התוספת הזו כותבת נתונים למסוף. לאחר מכן, בואו נרשום עוד תוספת שיכתוב לקובץ:
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
חשוב לציין שעדיין יהיה צורך להגדיר את התוספות. לאחר שכבר יש לנו נספחים רשומים, נוכל לקבוע איזו רמת רישום תהיה בצמתים ובאילו נספחים ישמשו.

log4j.rootLogger=DebuG, Console, FILE

  • log4j.rootLogger פירושו שנקבע את הצומת הראשי, המכיל את כל היומנים;
  • אחרי סימן השוויון, המילה הראשונה מציינת באיזו רמה ומעלה היומנים יירשמו (במקרה שלנו, זה DEBUG);
  • לאחר מכן, לאחר הפסיק כל הנספחים שישמשו יוצגו.
כדי להגדיר צומת רישום ספציפי, עליך להשתמש בערך הבא:
log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
שבו log4j.logger.הוא משמש להגדרת צומת ספציפי, במקרה שלנו הוא נמצא com.github.romankh3.logginglecture. ועכשיו בואו נדבר על הגדרת ה-Console Appender:
# CONSOLE appender customisation
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
כאן אנו רואים שאנו יכולים להגדיר את הרמה שממנה התוספתן יעבד. מצב אמיתי: הודעה עם רמת המידע התקבלה בצומת ה-logging והועברה ל-Appender שמוקצה לו, אך ה-Appender, עם רמת התראה ומעלה, קיבל את היומן הזה, אבל לא עשה איתו כלום. לאחר מכן, עליך להחליט איזו תבנית תהיה בהודעה. אני משתמש ב-PatternLayout בדוגמה, אבל יש הרבה פתרונות שם בחוץ. הם לא ייחשפו במאמר זה. דוגמה להגדרת תוספת FILE:
# File appender customisation
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
כאן תוכלו להגדיר לאיזה קובץ יומנים ייכתבו, כפי שניתן לראות ממנו
log4j.appender.FILE.File=./target/logging/logging.log
ההקלטה עוברת לקובץ logging.log. כדי למנוע בעיות בגודל הקובץ, אתה יכול להגדיר את המקסימום: במקרה זה, 1MB. MaxBackupIndex - אומר כמה קבצים כאלה יהיו. אם נוצר יותר ממספר זה, הקובץ הראשון יימחק. כדי להסתכל על דוגמה אמיתית שבה מוגדר רישום, אתה יכול ללכת למאגר הפתוח ב- GitHub.

בואו נאחד את התוצאה

נסה לעשות את כל מה שתואר בעצמך:
  • צור פרויקט משלך בדומה לזה שבדוגמה למעלה.
  • אם יש לך ידע בשימוש ב-Maven, נשתמש בו; אם לא, אז הנה קישור למאמר שמתאר כיצד לחבר את הספרייה.

בואו נסכם את זה

  1. דיברנו על איזה פתרונות יש בג'אווה.
  2. כמעט כל ספריות הרישום הידועות נכתבו תחת שליטה של ​​אדם אחד :D
  3. למדנו מה צריך לרשום ומה לא.
  4. הבנו את רמות הרישום.
  5. התוודענו לצמתי רישום.
  6. בדקנו מה זה תוספת ולמה הוא מיועד.
  7. הגדרנו את הקובץ log4j.proterties שלב אחר שלב.

חומרים נוספים

  1. JavaRush: רישום. שחררו כדור של סטרס
  2. JavaRush: הרצאת לוגר
  3. Habr: רישום Java. שלום עולם
  4. Habr: רישום ג'אווה: סיפורו של סיוט
  5. יוטיוב: קורסי גולובך. רישום. חלק 1 , חלק 2 , חלק 3 , חלק 4
  6. Log4j: תוספת
  7. Log4j: פריסה
ראה גם מאמרים אחרים שלי:
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION