ලොගින් (Logging) කරන හැටි: INFO, DEBUG සහ Structured Logging - Sri Lankan Dev Guide

ලොගින් (Logging) කරන හැටි: INFO, DEBUG සහ Structured Logging
ආයුබෝවන් කට්ටියටම! කොහොමද ඉතින්? අද අපි කතා කරන්න යන්නේ අපේ Software Engineering ගමනේදී මග අරින්නම බැරි, ඒත් ගොඩක් අය එච්චර ගණන් නොගන්න වැදගත් මාතෘකාවක් ගැන – ඒ තමයි Logging. ඔයාලා දන්නවා ඇතිනේ, අපි code ලියනවා, application හදනවා. හැබැයි මේවා production එකට ගියාම මොනවා වෙනවද කියලා බලන්න විදිහක් නැත්නම්, අවුලක් ආවොත් හොයාගන්න විදිහක් නැත්නම්, වැඩේ හරි යන්නේ නෑනේ. අන්න ඒ වගේ තැනකදී තමයි ලොගින් කියන එක දේවල් බේරගන්න එන්නේ!
ඔයාලා කවදාහරි පාරේ යනකොට රථ වාහන පොලීසිය ට්රැෆික් පොතක් අරන් මොනවා හරි ලියාගන්නවා දැකලා ඇතිනේ. එහෙම නැත්නම්, ඔයාලගේ බැංකු ගිණුමේ තියෙන හැම ගනුදෙනුවක්ම (transaction) පොතක වාර්තා වෙනවා වගේ. මේවා ඔක්කොම එකම අරමුණකින් කරන්නේ – ඒ තමයි දේවල් වාර්තා කරලා තියාගන්න එක. අපේ software ලෝකෙත් මේක එහෙමමයි. Application එකක ඇතුලේ මොනවාද වෙන්නේ, මොන user කෙනෙක් මොන දේට access කළාද, මොන error එකක් ආවාද වගේ දේවල් වාර්තා කරලා තියාගන්න එකට තමයි අපි ලොගින් කියලා කියන්නේ.
ගොඩක් වෙලාවට අපි අලුතින් project එකක් පටන් ගත්තම ඉක්මනටම features ටිකක් හදලා production එකට දාන්න තමයි හදන්නේ. ඒත් ඔය අතරේදී logging වගේ දේවල් මග ඇරෙනවා. එහෙම වුණාම මොකද වෙන්නේ? දවසක් රෑට production එකේ error එකක් ආවම, ඒක මොකක්ද කියලා හොයාගන්න අමාරු වෙනවා. Code එකේ bug එකක් තියෙනවා නම්, ඒක trace කරන්න බැරි වෙනවා. අන්න ඒ වෙලාවට තමයි අපි ඔළුවට අත තියාගෙන කල්පනා කරන්නේ, "අපෝ, මට මේකේ හොඳට ලොග් ටිකක් දැම්මා නම් හරිනේ!" කියලා. අද අපි මේ පරණ වැරදි නැවත නොකර, හරියටම logging කරන්නේ කොහොමද කියලා ඉගෙන ගමු. විශේෂයෙන්ම, Logging Levels හරියට පාවිච්චි කරන හැටි සහ Structured Logging කියන නූතන ක්රමය අපේ applications වලට කොහොමද එකතු කරගන්නේ කියලත් බලමු.
ලොග් ලෙවල්ස් (Logging Levels) හරියට පාවිච්චි කරමු – INFO vs DEBUG
අපි ලොග් කරනකොට, ඒ ලොග් එකේ වැදගත්කම අනුව අපි levels පාවිච්චි කරනවා. නිකමට හිතන්නකෝ, අපිට පොලිසියට call එකක් දෙන්න වුණොත්, අපේ තියෙන ප්රශ්නේ හැටියට අපි call කරන්නේ 119, 117, නැත්නම් වෙනත් අංකයකට වෙන්න පුළුවන්. ඒ වගේම තමයි ලොගින් වලදීත්. ප්රධාන වශයෙන් මේ වගේ ලොග් ලෙවල්ස් තියෙනවා:
- DEBUG: ඉතාම සියුම් විස්තර, application එකේ flow එක trace කරන්න වගේ දේවල් වලට. Production එකේදී මේවා එච්චර අවශ්ය වෙන්නේ නෑ.
- INFO: application එකේ සාමාන්ය ක්රියාකාරිත්වය පෙන්නුම් කරන වැදගත් සිදුවීම්. (e.g., “User logged in”, “Order placed”).
- WARN: යම්කිසි අවවාදයක්, සම්පූර්ණ error එකක් නොවෙයි, නමුත් අවධානය යොමු කළ යුතු දෙයක්. (e.g., “Low disk space”, “Deprecated API used”).
- ERROR: application එකේ යම් කොටසක වැඩ කිරීම නතර වුණාම. (e.g., “Database connection failed”).
- FATAL/CRITICAL: application එක සම්පූර්ණයෙන්ම ක්රියා විරහිත වන, හෝ ක්රියා විරහිත වීමට ආසන්න වන බරපතලම වැරදි.
අද අපි මේකෙන් INFO සහ DEBUG කියන ලෙවල්ස් දෙක ගැන ගැඹුරින් කතා කරමු. මොකද, ගොඩක් අය පටලවා ගන්න තැන් දෙකක් මේවා.
INFO Level එක පාවිච්චි කරමු කොහොමද?
INFO level එක අපි පාවිච්චි කරන්නේ application එකේ ප්රධාන සිදුවීම් වාර්තා කරන්න. මේවා සාමාන්යයෙන් production environment එකේදී අපි බලන්න බලාපොරොත්තු වෙන දේවල්. මේවායින් අපිට application එකේ flow එක ගැන හොඳ අවබෝධයක් ගන්න පුළුවන්. උදාහරණයක් විදිහට:
- User කෙනෙක් login වෙනවා.
- Order එකක් place කරනවා.
- යම්කිසි process එකක් සාර්ථකව අවසන් වෙනවා.
- Application එක start වෙනවා, stop වෙනවා.
මේවා application එකේ 'කතන්දරේ' වගේ. අපි මේවායින් තමයි දවස අවසානයේදී application එක කොහොමද වැඩ කරන්නේ කියලා දැනගන්නේ.
Python උදාහරණය:
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def login_user(username):
logging.info(f"User '{username}' attempted to log in.")
# ... (login logic)
if username == "admin": # Just an example
logging.info(f"User '{username}' logged in successfully.")
return True
else:
logging.warning(f"Invalid credentials for user '{username}'.")
return False
login_user("admin")
login_user("john_doe")
DEBUG Level එක පාවිච්චි කරමු කොහොමද?
DEBUG level එක තමයි application එකේ 'අභ්යන්තර රහස්'. මේවා පාවිච්චි කරන්නේ සංවර්ධනය කරන වෙලාවේදී (development) නැත්නම් යම්කිසි ගැටලුවක් ආවම ඒක විසඳගන්න (troubleshooting) විතරයි. DEBUG ලොග් වලින් අපිට code එකේ line by line flow එක, variable values, function calls වගේ ඉතාම සියුම් විස්තර ගන්න පුළුවන්. මේවා production එකේදී දාලා තිබ්බොත් log file එක අති විශාල වෙන්න පුළුවන්, ඒ වගේම production performance එකටත් බලපාන්න පුළුවන්. ඒ නිසා production එකේදී සාමාන්යයෙන් DEBUG ලොග් disabled කරලා තියෙන්නේ.
DEBUG ලොග් දානකොට පරිස්සම් වෙන්න ඕනේ, sensitive data (personal information, passwords, API keys) මේවාට ඇතුළත් කරන්නේ නැතුව. මොකද මේවා log file එකට ගියොත් security risk එකක්.
Python උදාහරණය:
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
def process_data(data):
logging.debug(f"Starting data processing for data: {data}")
result = data * 2 # Simple operation
logging.debug(f"Intermediate result after multiplication: {result}")
# ... more complex logic
final_result = result + 10
logging.debug(f"Final result before returning: {final_result}")
return final_result
logging.info("Application started.")
processed = process_data(5)
logging.info(f"Data processing complete. Processed value: {processed}")
මේ උදාහරණයේදී, අපි `logging.basicConfig(level=logging.DEBUG)` කියලා දැම්මොත්, INFO සහ DEBUG දෙකම log වෙනවා. හැබැයි `level=logging.INFO` කියලා දැම්මොත් DEBUG ලොග් වෙන්නේ නෑ. මේක තමයි ලොග් ලෙවල්ස් වල බලය! අපිට අවශ්ය විස්තර ප්රමාණය production එකේදී manage කරන්න පුළුවන්.
ස්ට්රක්චර්ඩ් ලොගින් (Structured Logging) – අලුත් ක්රමය
කලින් කාලේදී අපිට තිබ්බේ සාමාන්ය plain text logs. ඒවා කියවන්න ලේසියි. හැබැයි, application එක ලොකු වෙනකොට, ලොග් ගොඩක් එනකොට, මේ plain text logs analyze කරන එක හරිම අමාරුයි. 'අයියෝ, මේකේ error එකක් හොයන්න ඕනේ, මට user ID එක දාලා ෆිල්ටර් කරන්න බෑනේ!' වගේ ප්රශ්න එනවා. අන්න එතකොට තමයි Structured Logging කියන concept එක අපිට උදව් කරන්න එන්නේ.
Structured Logging කියන්නේ ලොග් කරන data එක structured format එකකට (ගොඩක් වෙලාවට JSON වලට) දාලා තියාගන්න එක. මේකේදී අපි key-value pairs විදිහට තමයි ලොග් කරන්නේ. මේකේ වාසිය තමයි, මේ වගේ structured data එකක් අපිට Log management tools (Splunk, ELK Stack - Elasticsearch, Logstash, Kibana, Grafana Loki) පාවිච්චි කරලා ලේසියෙන් search කරන්න, filter කරන්න, aggregate කරන්න සහ visualize කරන්න පුළුවන් වීම.
සාමාන්ය ලොගින් (Unstructured Logging) vs. ස්ට්රක්චර්ඩ් ලොගින් (Structured Logging)
Unstructured Log:
2023-10-27 10:30:15 INFO User 'alice' logged in successfully from IP: 192.168.1.100
2023-10-27 10:30:20 ERROR Failed to connect to database for user 'bob'. Error: Connection timed out.
මේක කියවන්න ලේසියි. හැබැයි මේකේ `user`, `IP`, `error message` වගේ දේවල් ටික ටික parse කරලා ගන්න අමාරුයි. දවසකට ලොග් දහස් ගණනක් එනකොට මේකේ යමක් හොයාගන්න එක ලොකු අභියෝගයක්.
Structured Log (JSON format):
{
"timestamp": "2023-10-27T10:30:15.123Z",
"level": "INFO",
"message": "User logged in successfully.",
"user_id": "alice",
"ip_address": "192.168.1.100",
"event_type": "auth"
}
{
"timestamp": "2023-10-27T10:30:20.456Z",
"level": "ERROR",
"message": "Failed to connect to database.",
"user_id": "bob",
"error_code": "DB_CONN_TIMEOUT",
"component": "database_service"
}
දැන් බලන්න, මේකේදී හැම detail එකක්ම වෙනම key-value pair එකක් විදිහට තියෙනවා. අපිට පුළුවන් Elasticsearch එකේ ගිහින් `user_id: "bob"` කියලා search කරන්න. නැත්නම් `level: "ERROR" AND component: "database_service"` කියලා search කරන්න. මේකෙන් මොන තරම් වෙලාවක් ඉතුරු වෙනවද කියන එක හිතාගන්නවත් බැරි වෙයි!
ස්ට්රක්චර්ඩ් ලොගින් (Structured Logging) අපේ app එකට එකතු කරගමු
ගොඩක් programmming languages වල structured logging support කරන libraries තියෙනවා. Python වලට `structlog`, Java වලට Logback/Log4j2 එක්ක JSON layout, Node.js වලට Pino/Winston වගේ ඒවා පාවිච්චි කරන්න පුළුවන්.
Python උදාහරණය (structlog library එකෙන්):
මුලින්ම `structlog` install කරගමු:
pip install structlog
ඊළඟට, code එකේදී use කරන හැටි බලමු:
import logging
import sys
import structlog
# Configure standard logging to output to console
logging.basicConfig(
format="%(message)s",
stream=sys.stdout,
level=logging.INFO
)
# Configure structlog
structlog.configure(
processors=[
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.StackInfoRenderer(),
structlog.dev.ConsoleRenderer() # For development, can be replaced with JSONRenderer for production
],
logger_factory=structlog.stdlib.LoggerFactory(),
wrapper_class=structlog.stdlib.BoundLogger,
cache_logger_on_first_use=True,
)
def get_logger(name):
return structlog.get_logger(name)
# --- Usage --- #
logger = get_logger("my_app.auth")
def login_user(username, password):
logger.debug("Login attempt started", username=username)
if username == "admin" and password == "secure_pass":
logger.info("User logged in successfully", username=username, ip_address="192.168.1.100", event_type="auth_success")
return True
else:
logger.warning("Failed login attempt", username=username, reason="invalid_credentials")
return False
def process_order(order_id, user_id, amount):
logger.info("Processing order", order_id=order_id, user_id=user_id, amount=amount)
try:
# Simulate a database error
if order_id == "ORDER_003":
raise ValueError("Database connection error")
logger.info("Order processed successfully", order_id=order_id, status="completed")
except Exception as e:
logger.error("Error processing order", order_id=order_id, user_id=user_id, error_message=str(e), component="order_service")
login_user("admin", "secure_pass")
login_user("john", "wrong_pass")
process_order("ORDER_001", "user_a", 150.00)
process_order("ORDER_002", "user_b", 250.00)
process_order("ORDER_003", "user_c", 500.00)
logger.info("Application shutting down.", uptime_minutes=15)
මේ උදාහරණයේදී, අපි `structlog.dev.ConsoleRenderer()` පාවිච්චි කරලා තියෙන්නේ development වලදී console එකට ලස්සනට formatted output එකක් ගන්න. Production වලදී නම් `structlog.processors.JSONRenderer()` එකට මාරු කරන්න පුළුවන්. එතකොට log file එකට JSON lines විදිහට තමයි ලියවෙන්නේ. මේකේදී අපි `username=username`, `ip_address="192.168.1.100"` වගේ key-value pairs කෙලින්ම logger එකට pass කරනවා. Structlog ඒවා ස්වයංක්රීයව JSON object එකට ඇතුලත් කරනවා.
ප්රැක්ටිකල් ටිප්ස් (Practical Tips) සහ හොඳම පුරුදු (Best Practices)
හරි, දැන් අපි ලොග් කරන හැටි, ලෙවල්ස් ගැන, structured logging ගැන දන්නවා. දැන් බලමු මේවා හරියටම පාවිච්චි කරන්න තව මොනවද කරන්න ඕනේ කියලා.
- Over-logging: හැම දේම log කරන්න ගියොත් log files විශාල වෙනවා, disk space යනවා, performance එකට බලපානවා, අනවශ්ය noise එක වැඩි වෙනවා.
- Under-logging: ප්රමාණවත් තරම් log නොකළොත්, ගැටලුවක් ආවම ඒක හොයාගන්න අමාරු වෙනවා.
Log Levels Runtime එකේදී වෙනස් කරන්න පුළුවන් වෙන්න සලස්වන්න:
සමහර logging frameworks වලට පුළුවන් runtime එකේදී log level එක වෙනස් කරන්න. මේකෙන් production එකේදී ගැටලුවක් ආවොත්, application එක restart නොකරම DEBUG level එකට මාරු වෙලා වැඩි විස්තර ලබාගන්න පුළුවන්. ගැටලුව විසඳුවාට පස්සේ ආයෙත් INFO level එකට මාරු කරන්නත් පුළුවන්.
Centralized Logging System එකක් පාවිච්චි කරන්න:
විශාල distributed systems වලදී, servers ගොඩක logs එකතු වෙනකොට, ඒ හැම server එකකටම ගිහින් logs බලන එක ප්රායෝගික නැහැ. ඒ නිසා, Elasticsearch, Splunk, Graylog, Loki වගේ centralized logging system එකක් පාවිච්චි කරන්න පුරුදු වෙන්න. මේවාට හැම application එකකින්ම logs යවනවා. පස්සේ එක තැනකින් search කරන්න, analyze කරන්න පුළුවන්.
Log Rotation Configure කරන්න:
Log files නිතරම වර්ධනය වෙනවා. ඒ නිසා නියමිත කාලයකට හෝ ප්රමාණයකට පස්සේ log files rotate කරන්න (අලුත් එකක් පටන් අරන්, පරණ එක compress කරලා archive කරන එක). මේකෙන් disk space එක save කරගන්න පුළුවන්. `logrotate` වගේ tools මේකට පාවිච්චි කරන්න පුළුවන්.
Over-logging හෝ Under-logging කරන්න එපා:
මේ දෙක අතර සමබරතාවයක් තියාගන්න. DEBUG levels development වලට, INFO production වලට වගේ strategy එකක් තියාගන්න.
Context එකක් එකතු කරන්න:
හැම log message එකකටම පුළුවන් තරම් context එකක් එකතු කරන්න. උදාහරණයක් විදිහට, web request එකක් process කරනකොට, ඒ request එකට අදාළ `request_id`, `user_id`, `session_id` වගේ දේවල් හැම log එකකටම එකතු කරන්න. මේකෙන් error එකක් ආවම, ඒක අදාළ user කෙනාට, අදාළ request එකට සම්බන්ධ කරන්න පුළුවන් වෙනවා.
# Example with context in Python (using structlog)
logger.info("User performed action", user_id="user123", action="purchase", product_id="P456")
නියත Log Format එකක් පාවිච්චි කරන්න:
ඔබේ application එක පුරාවටම එකම logging format එකක් සහ standards ටිකක් පාවිච්චි කරන්න. මේකෙන් log analyse කරන එක පහසු වෙනවා. Structured logging පාවිච්චි කරනවා නම් මේක ස්වයංක්රීයවම වෙනවා.
Sensitive Data ලොග් කරන්න එපා:
මෙය ඉතාම වැදගත් දෙයක්. කිසිම වෙලාවක passwords, credit card numbers, PII (Personally Identifiable Information) වගේ sensitive data log file වලට ලියන්න එපා. සමහර වෙලාවට අපි request body එකම log කරන්න හදනවා. ඒ වෙලාවට මේ වගේ data තියෙන්න පුළුවන්. ඒ නිසා filter කරලා හෝ sanitize කරලා log කරන්න පුරුදු වෙන්න.
අවසන් වශයෙන්
ඉතින් යාලුවනේ, ඔයාලා දැක්කනේ logging කියන එක කොයිතරම් වැදගත්ද කියලා. මේක නිකම්ම text lines ටිකක් file එකකට ලියන එකක් නෙවෙයි, අපේ application වලට 'ඇස්' සහ 'කන්' දෙනවා වගේ වැඩක්. අපි log levels හරියට පාවිච්චි කරනවා නම්, අනවශ්ය information වලින් log files පුරවා නොගෙන, අවශ්ය දේ විතරක් log කරන්න පුළුවන්. ඒ වගේම, structured logging කියන එක මගින්, අනාගතයේදී අපේ logs analyse කරන එක, errors හොයන එක, performance එක monitor කරන එක ගොඩක් ලේසි වෙනවා.
මතක තියාගන්න, හොඳ software engineer කෙනෙක් කියන්නේ code ලියන්න විතරක් දන්න කෙනෙක් නෙවෙයි, තමන් ලියන code එක production එකේදී කොහොමද behave කරන්නේ කියලා තේරුම් ගන්නත් දක්ෂ කෙනෙක්. ඒකට logging කියන්නේ ප්රධානම tool එකක්. ඒ නිසා, ඔයාලගේ ඊළඟ project එක පටන් ගන්නකොට, මේ දේවල් මතක තියාගෙන, මුල ඉඳලම හොඳ logging strategy එකක් හදාගන්න. බැරි වෙලාවත් ඔයාලගේ production system එකේ රෑ මැදියමේ error එකක් ආවොත්, මේ හොඳ logging පුරුදු නිසා ඔයාලට පුළුවන් වෙයි ටක් ගාලා ඒක විසඳලා බඩු බේරගන්න! එතකොට ඉතින් BOSS ගෙන් අහන්නත් දෙයක් නෑ, ටක් ගාලා වැඩේ ඉවර කරලා නිදාගන්න පුළුවන්!
අද කතා කරපු දේවල් ඔයාලගේ ව්යාපෘති වලට එකතු කරගන්න උත්සාහ කරන්න. මොනවා හරි ප්රශ්න තියෙනවා නම්, නැත්නම් ඔයාලගේ අත්දැකීම් බෙදාගන්න ඕනේ නම්, comment section එකේ ලියන්න. අපි හැමෝම එකතු වෙලා ඉගෙන ගමු!
ආයෙත් දවසක තවත් වටිනා මාතෘකාවකින් හමු වෙමු! එතකල් පරිස්සමින් ඉන්න!